home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Panel Editor / Source / PanelEditor.cpp < prev    next >
Encoding:
Text File  |  1995-12-08  |  146.3 KB  |  4,680 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.  
  3.     File:            PanelEditor.cpp
  4.     
  5.     Written by:        Steve Smith
  6.     
  7.     Copyright:        © 1995 by Apple Computer, Inc., all rights reserved.
  8.     
  9.     Description:    PanelEditor demonstrates the most basic functions and
  10.                     responsibilities of an OpenDoc™ leaf part.
  11.     
  12.     
  13.     Demonstrates:    The following recipes were used in implementing the
  14.                     PanelEditor:
  15.                      1. Open
  16.                      2. Adding A Display Frame
  17.                      3. Adding A Facet
  18.                      4. Part Drawing
  19.                      5. Refcounting Geometry
  20.                      6. ViewTypes & Presentations
  21.                      7. Display Frame 'ternalization
  22.                      8. Part Init & Externalization
  23.                      9. Part Init & partWrapper
  24.                     10. Part Storage Model
  25.                     11. Persistent Reference
  26.                     12. RefCounting
  27.                     13. Storage Unit
  28.                     14. Activation
  29.                     15. Basic Event Handling
  30.                     16. Menus
  31.                     17. Windows & Dialogs
  32.                     18. Exception Handling
  33.                     19. Memory Manager
  34.                     20. Using Resources
  35.                     21. Lazy Frame Internalization
  36.                     22. Multiple Kind Support
  37.     
  38.     
  39.     Notes:            • For methods where it is necessary to call the parent class
  40.                     implementation, the calls are made from the SOM class. See
  41.                     som_PanelEditor.cpp and the Class Reference to know whether
  42.                     you need to call the parent class from any method.
  43.  
  44.                     • Panel Editor will, at some point, demonstrate a single source
  45.                     base for an "editor" and a "viewer". Throughout the code, you 
  46.                     will see "#ifndef PE_ViewerBuild". Any code wrapped by the
  47.                     ifdef is code that should not execute in the viewer version of
  48.                     the part/component/application. Though the implementation is
  49.                     incomplete, it should give you some preliminary ideas on how
  50.                     to structure your code so that you can provide both an editor
  51.                     and a viewer to your customers.
  52.     
  53. ------------------------------------------------------------------------------*/
  54.  
  55. // -- Compiler/Preprocessor Switches --
  56.  
  57. #ifndef _COMPILERDEFS_
  58. #include "CompDefs.h"
  59. #endif
  60.  
  61. // -- OpenDoc Utilities --
  62.  
  63. #ifndef _EXCEPT_
  64. // Exceptions define several important macros (ie. CHECKENV)
  65. // which are used in the SOM method dispatch glue. If Except.h
  66. // is not included early enough, exceptions may not be thrown
  67. // correctly when returning from a SOM method with the "ev" parameter set.
  68. #include <Except.h>
  69. #endif
  70.  
  71. // -- PanelEditor Includes --
  72.  
  73. #ifndef _PANELEDITORGLOBALS_
  74. #include "PanelEditorGlobals.h"
  75. #endif
  76.  
  77. #ifndef _PANELEDITOR_
  78. #include "PanelEditor.h"
  79. #endif
  80.  
  81. #ifndef _LISTITEM_
  82. #include "ListItem.h"
  83. #endif
  84.  
  85. #ifndef _SELECTION_
  86. #include "Selection.h"
  87. #endif
  88.  
  89. #ifndef _PANEL_
  90. #include "Panel.h"
  91. #endif
  92.  
  93. #ifndef _SCROLLINGLIST_
  94. #include "ScrollingList.h"
  95. #endif
  96.  
  97. #ifndef _UNDOPE_
  98. #include "UndoPE.h"
  99. #endif
  100.  
  101. #ifndef _SCROLLBAR_
  102. #include "Scrollbar.h"
  103. #endif
  104.  
  105. #ifndef _FRAMEINFO_
  106. #include "FrameInfo.h"
  107. #endif
  108.  
  109. #ifndef _PANELEDITORDEF_
  110. #include "PanelEditorDef.h"
  111. #endif
  112.  
  113. #ifndef _PANELEDITORUTILS_
  114. #include "PanelEditorUtils.h"
  115. #endif
  116.  
  117. #ifndef _SAMPLECOLLECTIONS_
  118. #include "SampleCollections.h"
  119. #endif
  120.  
  121. #ifndef _PRINTER_
  122. #include "Printer.h"
  123. #endif
  124.  
  125. // -- OpenDoc Includes --
  126.  
  127. #ifndef _ODTYPES_
  128. #include <ODTypes.h>
  129. #endif
  130.  
  131. #ifndef SOM_ODPart_xh
  132. #include <Part.xh>
  133. #endif
  134.  
  135. #ifndef SOM_ODFacet_xh
  136. #include <Facet.xh>
  137. #endif
  138.  
  139. #ifndef SOM_ODFrame_xh
  140. #include <Frame.xh>
  141. #endif
  142.  
  143. #ifndef SOM_ODFrameFacetIterator_xh
  144. #include <FrFaItr.xh>
  145. #endif
  146.  
  147. #ifndef SOM_ODArbitrator_xh
  148. #include <Arbitrat.xh>
  149. #endif
  150.  
  151. #ifndef SOM_Module_OpenDoc_Foci_defined
  152. #include <Foci.xh>
  153. #endif
  154.  
  155. #ifndef SOM_ODShape_xh
  156. #include <Shape.xh>
  157. #endif
  158.  
  159. #ifndef SOM_Module_OpenDoc_StdProps_defined
  160. #include <StdProps.xh>
  161. #endif
  162.  
  163. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  164. #include <StdTypes.xh>
  165. #endif
  166.  
  167. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  168. #include <StdDefs.xh>
  169. #endif
  170.  
  171. #ifndef SOM_Module_OpenDoc_Commands_defined
  172. #include <CmdDefs.xh>
  173. #endif
  174.  
  175. #ifndef SOM_ODDraft_xh
  176. #include <Draft.xh>
  177. #endif
  178.  
  179. #ifndef SOM_ODStorageUnit_xh
  180. #include <StorageU.xh>
  181. #endif
  182.  
  183. #ifndef SOM_ODStorageUnitView_xh
  184. #include <SUView.xh>
  185. #endif
  186.  
  187. #ifndef SOM_ODTransform_xh
  188. #include <Trnsform.xh>
  189. #endif
  190.  
  191. #ifndef SOM_ODFocusSet_xh
  192. #include <FocusSet.xh>
  193. #endif
  194.  
  195. #ifndef SOM_ODMenuBar_xh
  196. #include <MenuBar.xh>
  197. #endif
  198.  
  199. #ifndef SOM_ODWindow_xh
  200. #include <Window.xh>
  201. #endif
  202.  
  203. #ifndef SOM_ODWindowState_xh
  204. #include <WinStat.xh>
  205. #endif
  206.  
  207. #ifndef SOM_ODCanvas_xh
  208. #include <Canvas.xh>
  209. #endif
  210.  
  211. #ifndef SOM_ODSession_xh
  212. #include <ODSessn.xh>
  213. #endif
  214.  
  215. #ifndef SOM_ODDragAndDrop_xh
  216. #include <DragDrp.xh>
  217. #endif
  218.  
  219. #ifndef SOM_ODDragItemIterator_xh
  220. #include <DgItmIt.xh>
  221. #endif
  222.  
  223. #ifndef SOM_ODClipboard_xh
  224. #include <Clipbd.xh>
  225. #endif
  226.  
  227. #ifndef SOM_ODUndo_xh
  228. #include <Undo.xh>
  229. #endif
  230.  
  231. // -- OpenDoc Utilities --
  232.  
  233. #ifndef _ITEXT_
  234. #include <IText.h>
  235. #endif
  236.  
  237. #ifndef _FOCUSLIB_
  238. #include <FocusLib.h>
  239. #endif
  240.  
  241. #ifndef _USERSRCM_
  242. #include <UseRsrcM.h>
  243. #endif
  244.  
  245. #ifndef _ODMEMORY_
  246. #include <ODMemory.h>
  247. #endif
  248.  
  249. #ifndef _ODNEW_
  250. #include <ODNew.h>
  251. #endif
  252.  
  253. #ifndef _ISOSTR_
  254. #include <ISOStr.h>
  255. #endif
  256.  
  257. #ifndef _ODUTILS_
  258. #include <ODUtils.h>
  259. #endif
  260.  
  261. #ifndef _PLFMDEF_
  262. #include <PlfmDef.h>
  263. #endif
  264.  
  265. #ifndef _STORUTIL_
  266. #include <StorUtil.h>
  267. #endif
  268.  
  269. #ifndef _STDTYPIO_
  270. #include <StdTypIO.h>
  271. #endif
  272.  
  273. #ifndef _TEMPOBJ_
  274. #include <TempObj.h>
  275. #endif
  276.  
  277. #ifndef _TEMPITER_
  278. #include <TempIter.h>
  279. #endif
  280.  
  281. #ifndef _WINUTILS_
  282. #include <WinUtils.h>
  283. #endif
  284.  
  285. // -- Macintosh Includes --
  286.  
  287. #ifndef __ERRORS__
  288. #include <Errors.h>
  289. #endif
  290.  
  291. #ifndef __DRAG__
  292. #include <Drag.h>
  293. #endif
  294.  
  295. #ifndef __RESOURCES__
  296. #include <Resources.h>
  297. #endif
  298.  
  299. #ifndef __DIALOGS__
  300. #include <Dialogs.h>
  301. #endif
  302.  
  303. #ifndef __TOOLUTILS__
  304. #include <ToolUtils.h>
  305. #endif
  306.  
  307. #ifndef __ICONS__
  308. #include <Icons.h>
  309. #endif
  310.  
  311. #ifndef __QUICKDRAW__
  312. #include <Quickdraw.h>
  313. #endif
  314.  
  315. #ifndef __LOWMEM__
  316. #include <LowMem.h>
  317. #endif
  318.  
  319. #ifndef __GXMATH__
  320. #include <GXMath.h>
  321. #endif
  322.  
  323. #pragma segment PanelEditor
  324.  
  325.  
  326. //==============================================================================
  327. // PanelEditor
  328. //==============================================================================
  329.  
  330. //------------------------------------------------------------------------------
  331. // Method:        Constructor
  332. // Origin:        Panel Editor
  333. //
  334. // Description:    This is the C++ class constructor.
  335. //
  336. // Warnings:    You are not allowed to throw an exception from this method.
  337. //------------------------------------------------------------------------------
  338.  
  339. PanelEditor::PanelEditor()
  340. {
  341.     SOM_Trace("PanelEditor","Constructor");
  342.  
  343.     fSelf                = kODNULL;
  344.     fDisplayFrames        = kODNULL;
  345.     fEmbeddedParts        = kODNULL;
  346.     fSelection            = kODNULL;
  347.     fPanel                = kODNULL;
  348.     fList                = kODNULL;
  349.     fPrinter            = kODNULL;
  350.     
  351.     fDirty                = kODFalse;
  352.     fNegotiating        = kODFalse;
  353.     fReadOnlyStorage    = kODFalse;
  354. }
  355.  
  356. //------------------------------------------------------------------------------
  357. // Method:        Destructor
  358. // Origin:        Panel Editor
  359. //
  360. // Description:    This is the C++ class destructor.
  361. //
  362. // Warnings:    You are not allowed to throw an exception from this method.
  363. //------------------------------------------------------------------------------
  364.  
  365. PanelEditor::~PanelEditor()
  366. {
  367.     SOM_Trace("PanelEditor","Destructor");
  368. }
  369.  
  370. //==============================================================================
  371. #pragma mark    • Getters/Setters •
  372. //==============================================================================
  373.  
  374. //------------------------------------------------------------------------------
  375. // Method:        GetSelf
  376. // Origin:        Panel Editor
  377. //
  378. // Description:    Return the partwrapper object for this part.
  379. //
  380. //                This is used by the part to ?????
  381. //------------------------------------------------------------------------------
  382.  
  383. ODPart* PanelEditor::GetSelf()
  384. {
  385.     return fSelf;
  386. }
  387.  
  388. //------------------------------------------------------------------------------
  389. // Method:        GetEmbeddedItems
  390. // Origin:        Panel Editor
  391. //
  392. // Description:    Return the partwrapper object for this part.
  393. //
  394. //                This is used by the part to ?????
  395. //------------------------------------------------------------------------------
  396.  
  397. COrderedList* PanelEditor::GetEmbeddedItems()
  398. {
  399.     return fEmbeddedParts;
  400. }
  401.  
  402. //==============================================================================
  403. #pragma mark    • Initialization •
  404. //==============================================================================
  405.  
  406. //------------------------------------------------------------------------------
  407. // Method:        InitPart
  408. // Origin:        ODPart
  409. //
  410. // Description:    This method is called when a new instance of this part is being
  411. //                created. The part should prepare itself to run.
  412. //
  413. // Parent:        The part's parent class was called before this method was
  414. //                dispatched to (see som_PanelEditor.cpp).
  415. //
  416. // Warning:        It is not appropriate to require user interaction while
  417. //                stationery is being created. Do not present the user with error
  418. //                dialogs or splash screens from this method.
  419. //------------------------------------------------------------------------------
  420.  
  421. void PanelEditor::InitPart( Environment*    ev,
  422.                            ODStorageUnit*    storageUnit,
  423.                            ODPart*            partWrapper )
  424. {
  425.     SOM_Trace("PanelEditor","InitPart");
  426.  
  427.     TRY
  428.         // To allow editor swapping (translation) at runtime, OpenDoc requires
  429.         // that we pass in a "reference" to ourselves when interacting with the
  430.         // API (ie. WindowState::RegisterWindow(), Dispatcher::RegisterIdle, etc).
  431.         // The "partWrapper" passed to us here and in InitPartFromStorage is the
  432.         // "reference" OpenDoc is asking us to use.
  433.         fSelf = partWrapper;
  434.     
  435.         // We are being created, either as part of generating stationery or
  436.         // by some editor instantiating the part, so the destination storage
  437.         // must be writeable.
  438.         fReadOnlyStorage = kODFalse;
  439.             
  440.         // Call the common initialization code to get set up.
  441.         this->Initialize(ev);
  442.  
  443.         // Create the printer object.
  444.         fPrinter = CPrinter::New(ev, storageUnit);
  445.     
  446.         // Since we have just been created, our state/content info has
  447.         // never been written out, so setting our "dirty" flag will
  448.         // give us a chance to do that.
  449.         this->SetDirty(ev);
  450.     
  451.     CATCH_ALL
  452.         // Clean up will occur in the destructor which will be called
  453.         // shortly after we return the error.
  454.         RERAISE;
  455.     ENDTRY
  456. }
  457.  
  458. //------------------------------------------------------------------------------
  459. // Method:        InitPartFromStorage
  460. // Origin:        ODPart
  461. //
  462. // Description:    This method is called when a document/stationery is being opened
  463. //                or when the part is internalized by its containing part. The
  464. //                part should merely read in the saved state/content and
  465. //                initialize itself. The part must not alter its storage unit;
  466. //                otherwise, the "Save" menu item becomes enabled without the user
  467. //                actually having made a change to the document.
  468. //
  469. // Parent:        The part's parent class was called before this method was
  470. //                dispatched to (see som_SamplePart.cpp).
  471. //------------------------------------------------------------------------------
  472.  
  473. void PanelEditor::InitPartFromStorage( Environment*        ev,
  474.                                       ODStorageUnit*    storageUnit,
  475.                                       ODPart*            partWrapper )
  476. {
  477.     SOM_Trace("PanelEditor","InitPartFromStorage");
  478.  
  479.     TRY
  480.         // To allow editor swapping (translation) at runtime, OpenDoc requires
  481.         // that we pass in a "reference" to ourselves when interacting with the
  482.         // API (ie. WindowState::RegisterWindow(), Dispatcher::RegisterIdle, etc).
  483.         // The "partWrapper" passed to us here and in InitPart is the
  484.         // "reference" OpenDoc is asking us to use.
  485.         fSelf = partWrapper;
  486.             
  487.         // Are we being opened from a read-only draft? If so, we cannot
  488.         // write anything back out to our storage unit.
  489.         fReadOnlyStorage = ( ODGetDraft(ev,storageUnit)->
  490.                                 GetPermissions(ev) < kODDPSharedWrite );
  491.             
  492.         // Call the common initialization code to get set up.
  493.         this->Initialize(ev);
  494.     
  495.         // Create the printer object.
  496.         fPrinter = CPrinter::New(ev, storageUnit);
  497.     
  498.         // Read in the state the part was in when it was last Externalized.
  499.         // This allows the part to present the same "environment" the user
  500.         // had the part set up in the last time it was edited.
  501.         this->InternalizeStateInfo(ev, storageUnit);
  502.     
  503.         // Read in the contents for your part editor.
  504.         this->InternalizeContent(ev, storageUnit);
  505.  
  506.     CATCH_ALL
  507.         // Clean up will occur in the destructor which will be called
  508.         // shortly after we return the error.
  509.         RERAISE;
  510.     ENDTRY
  511. }
  512.  
  513. //------------------------------------------------------------------------------
  514. // Method:        Initialize
  515. // Origin:        Panel Editor
  516. //
  517. // Description:    This method is called during the initialization of the part. The
  518. //                method is used to initialize all fields of the part and to
  519. //                convert ISO types to tokens for faster comparisons throughout
  520. //                the code.
  521. //
  522. //                If an exception is thrown in this method, it wil be propogated
  523. //                back to OpenDoc which will call our ReleaseAll() method and the
  524. //                class destructor. All memory allocated here will be cleaned up
  525. //                in the ReleaseAll() method.
  526. //------------------------------------------------------------------------------
  527.  
  528. void PanelEditor::Initialize( Environment*    ev )
  529. {
  530.     SOM_Trace("PanelEditor","Initialize");
  531.  
  532.     // Grab a reference to the Session object. This is merely for
  533.     // convenience.
  534.     ODSession* session = ODGetSession(ev, fSelf);
  535.         
  536.     // Create a list to keep track of the frames we are being
  537.     // displayed in. Also used for maintenance (i.e., Purging memory).
  538.     fDisplayFrames = new CList;
  539.     
  540.     // Create a list to manage the embedded "list item" objects.
  541.     fEmbeddedParts = new COrderedList;
  542.     
  543.     // Create our selection object.
  544.     fSelection = new CSelection(this, session);
  545.     fSelection->InitSelection();
  546.     
  547.     // Create our scrolling list frame proxy object.
  548.     fList = new CScrollingList;
  549.     fList->InitScrollingList(ev, this);
  550.  
  551.     // Create our panel frame proxy object.
  552.     fPanel = new CPanel;
  553.     fPanel->InitPanel();
  554.  
  555.     // First check to see if the library's global variables have
  556.     // been initialized (meaning another part instantiation is already
  557.     // running).
  558.  
  559.     if ( gGlobalsUsageCount == 0 )
  560.     {
  561.         // Create our globals space. We store the globals in a struct so
  562.         // that we can put them in temp mem. Otherwise, CFM loads the globals
  563.         // with the data fragment of a CFM library in the application heap.
  564.         gGlobals = new PanelEditorGlobals;
  565.     
  566.         // It is required that parts instantiate their menu bars from 
  567.         // the base OpenDoc menu bar. This maintains consistency in the
  568.         // default menu items and their placement.
  569.         // Since the object is a copy, we can add and subtract menus and
  570.         // items without affecting other running parts.
  571.         gGlobals->fMenuBar = session->GetWindowState(ev)->CopyBaseMenuBar(ev);
  572.  
  573.         // We will be using the following foci (shared resources) in this
  574.         // part. For convenience, we tokenize the values here and store
  575.         // them for equivalence tests in the activation methods.
  576.         gGlobals->fSelectionFocus = session->Tokenize(ev, kODSelectionFocus);
  577.         gGlobals->fMenuFocus = session->Tokenize(ev, kODMenuFocus);
  578.         gGlobals->fKeyboardFocus = session->Tokenize(ev, kODKeyFocus);
  579.         gGlobals->fModalFocus = session->Tokenize(ev, kODModalFocus);
  580.         gGlobals->fClipboardFocus = session->Tokenize(ev, kODClipboardFocus);
  581.     
  582.         // Also for convenience, we tokenize our part's main presentation
  583.         // and the standard view types.
  584.         gGlobals->fUndefinedPresentation = session->Tokenize(ev, kODPresDefault);
  585.         gGlobals->fMainPresentation = session->Tokenize(ev, kMainPresentation);
  586.         gGlobals->fListPresentation = session->Tokenize(ev, kListPresentation);
  587.     
  588.         gGlobals->fFrameView = session->Tokenize(ev, kODViewAsFrame);
  589.         gGlobals->fLargeIconView = session->Tokenize(ev, kODViewAsLargeIcon);
  590.         gGlobals->fSmallIconView = session->Tokenize(ev, kODViewAsSmallIcon);
  591.         gGlobals->fThumbnailView = session->Tokenize(ev, kODViewAsThumbnail);
  592.     
  593.         // Lastly, we will package the menu and selection focus
  594.         // so that we can request the "set" at activation time.
  595.         gGlobals->fUIFocusSet = session->GetArbitrator(ev)->CreateFocusSet(ev);
  596.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fMenuFocus);
  597.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fKeyboardFocus);
  598.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fSelectionFocus);
  599.             
  600.         // Determine what Script/Language the part is localized for.
  601.         // This is important/necessary for creating OpenDoc's text objects.
  602.         GetEditorScriptLanguage(ev, &gGlobals->fEditorsScript, &gGlobals->fEditorsLanguage);
  603.         GetScriptFontSize(ev, gGlobals->fEditorsScript, &gGlobals->fScriptFont, &gGlobals->fScriptFontSize);
  604.  
  605.         // Get the "untitled" item string from our resources.
  606.         Str31 text;
  607.         ODGetIndString(text, kUntitledNameResID, kUntitledName);
  608.         gGlobals->fUntitledName = CreateIText(gGlobals->fEditorsScript, gGlobals->fEditorsLanguage, (StringPtr)&text);
  609.     
  610.         // The first client of the global variables is running.
  611.         gGlobalsUsageCount = 1;
  612.     }
  613.     else
  614.     // If the globals have been initialized, we just bump the "usage" count so
  615.     // that we know how many part instances are using them.
  616.     {
  617.         gGlobalsUsageCount++;
  618.     }
  619. }
  620.  
  621. //==============================================================================
  622. #pragma mark    • Storage •
  623. //==============================================================================
  624.  
  625. //------------------------------------------------------------------------------
  626. // Method:        Release
  627. // Origin:        ODPart
  628. //
  629. // Description:    This method is called each time an object releases a reference
  630. //                to the part. If the refcount falls to 0, the part should
  631. //                release the fSelf part reference.
  632. //
  633. // Parent:        The part's parent class was called before this method was
  634. //                dispatched to (see som_SamplePart.cpp).
  635. //
  636. // Warning:        If the part releases any other object when the refcount falls to
  637. //                zero, it will need to override the Acquire method so
  638. //                that the object can be referenced again if the parts refcount
  639. //                should be incremented before it is deleted.
  640. //------------------------------------------------------------------------------
  641.  
  642. void PanelEditor::Release( Environment* ev )
  643. {
  644.     SOM_Trace("PanelEditor","Release");
  645.  
  646.     if (fSelf->GetRefCount(ev) == 0)
  647.         ODGetDraft(ev, fSelf)->ReleasePart(ev, fSelf);
  648. }
  649.  
  650. //------------------------------------------------------------------------------
  651. // Method:        ReleaseAll
  652. //
  653. // Description:    This method is called just prior to the part being deleted by
  654. //                the Draft. The part must release all references to all
  655. //                refcounted objects it has stored internally; not doing so, will
  656. //                cause an "invalid ref count" exception/error at some later time.
  657. //------------------------------------------------------------------------------
  658.  
  659. void PanelEditor::ReleaseAll( Environment* ev )
  660. {
  661.     SOM_Trace("PanelEditor","ReleaseAll");
  662.  
  663.     TRY
  664.         // Delete the selection object.
  665.         ODDeleteObject(fSelection);
  666.         // Delete the panel object.
  667.         ODDeleteObject(fPanel);
  668.         // Delete the scrolling list object.
  669.         ODDeleteObject(fList);
  670.         
  671.         // Delete the printer object.
  672.         ODDeleteObject(fPrinter);
  673.  
  674.         // If the last part instance using the globals is released,
  675.         // we need to delete the globals.
  676.         
  677.         if ( --gGlobalsUsageCount == 0 )
  678.         {
  679.             // Release the menubar.
  680.             ODReleaseObject(ev, gGlobals->fMenuBar);
  681.             
  682.             // But first, we need to delete the objects we created
  683.             // and stored in the globals struct.
  684.             ODDeleteObject(gGlobals->fUIFocusSet);
  685.             DisposeIText(gGlobals->fUntitledName);
  686.  
  687.             // Release the thumbnail (PICT) resource.
  688.             if ( gGlobals->fThumbnail )
  689.             {
  690.                 ReleaseResource(gGlobals->fThumbnail);
  691.                 gGlobals->fThumbnail = kODNULL;
  692.             }
  693.             
  694.             // Now, clean up the globals struct.
  695.             ODDeleteObject(gGlobals);
  696.         }
  697.     
  698.         // Release our display frames.
  699.         if ( fDisplayFrames )
  700.         {
  701.             CListIterator fiter(fDisplayFrames);
  702.             for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  703.                     fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  704.             {
  705.                 // Delete the proxy object and its contents. The frame's
  706.                 // refcount will be decremented in the proxy destructor.
  707.                 fiter.RemoveCurrent();
  708.                 delete proxy;
  709.             }
  710.         
  711.             // Delete the display frame collection.
  712.             ODDeleteObject(fDisplayFrames);
  713.         }
  714.         
  715.         // Release all the embedded items.
  716.         if ( fEmbeddedParts )
  717.         {
  718.             COrdListIterator fiter(fEmbeddedParts);
  719.             for ( CListItem* item = (CListItem*)fiter.First();
  720.                     fiter.IsNotComplete();
  721.                     item = (CListItem*)fiter.Next() )
  722.             {
  723.                 fiter.RemoveCurrent();
  724.                 item->Release(ev);
  725.             }
  726.  
  727.             ODDeleteObject(fEmbeddedParts);
  728.         }
  729.  
  730.     CATCH_ALL
  731.         // If something goes wrong while we are cleaning up, we must
  732.         // let the Draft now because there may be some refcounted objects
  733.         // which did not get released. Not to mention, possible memory
  734.         // leaks.
  735.         RERAISE;        
  736.     ENDTRY
  737. }
  738.  
  739. //------------------------------------------------------------------------------
  740. // Method:        Purge
  741. // Origin:        ODPart
  742. //
  743. // Description:    This method is called when the OpenDoc requires more memory for
  744. //                allocating objects and just before a part is deleted. The part
  745. //                should free up as much memory as it can.
  746. //
  747. //                The part determines which views are being "used" in its display
  748. //                frames. The resources for the unused view types are then purged.
  749. //------------------------------------------------------------------------------
  750.  
  751. ODSize PanelEditor::Purge(    Environment*    ev,
  752.                              ODSize            /*size*/ )
  753. {
  754.     SOM_Trace("PanelEditor","Purge");
  755.  
  756.     // Purge is called during the creation of stationery. However,
  757.     // we have not created our internal display frames list, so 
  758.     // trying to iterate over it would be fatal.
  759.     if ( fDisplayFrames == kODNULL ) return 0;
  760.     
  761.     ODSize         bytesFreed        = 0;
  762.     ODBoolean    usingThumbnail  = kODFalse;
  763.     
  764.     // Iterate over the frames we are displayed through and determine which
  765.     // view types are currently in use.
  766.     
  767.     CListIterator fiter(fDisplayFrames);
  768.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  769.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  770.     {
  771.         // If the display frame is real (has been "connected" or was "added")
  772.         // get its view type; otherwise, ignore it.
  773.         if ( proxy->FrameIsLoaded(ev) )
  774.         {
  775.             ODTypeToken    frameView = proxy->GetFrame(ev)->GetViewType(ev);
  776.             
  777.             if ( frameView == gGlobals->fThumbnailView )
  778.                 usingThumbnail = kODTrue;
  779.             
  780.             // Release the frame reference, but don't get rid of the
  781.             // proxy object because we're not done with the frame. If
  782.             // all parts release their references the frame will be
  783.             // purged from memory.
  784.             proxy->Purge(ev);
  785.         }
  786.     }
  787.     
  788.     // Based on the usage of the supported view types, free up as much
  789.     // memory as possible.
  790.  
  791.     if ( !usingThumbnail && (gGlobals->fThumbnail != kODNULL) )
  792.     {
  793.         bytesFreed += (ODSize) ODGetHandleSize(gGlobals->fThumbnail);
  794.         ReleaseResource(gGlobals->fThumbnail);
  795.         gGlobals->fThumbnail = kODNULL;
  796.     }
  797.     
  798.     return bytesFreed;
  799. }
  800.  
  801. //------------------------------------------------------------------------------
  802. // Method:        InternalizeStateInfo
  803. // Origin:        SamplePart
  804. //
  805. // Description:    This method is used to read in "state" information for the part.
  806. //                This is information related to the workings of the part editor,
  807. //                not the content.
  808. //
  809. //                The part writes out a list of weak references to its display
  810. //                frames. This allows the part to reuse the same display frames
  811. //                each time the document is opened. Those references are read
  812. //                back in and validated here.
  813. //
  814. // Note:        The function StorageUnitGetValue simplifies the use of
  815. //                ODByteArrary, which is required the StorageUnit interface. Look
  816. //                in StorUtil.h/cpp for an example of using the ODByteArray struct.
  817. //------------------------------------------------------------------------------
  818.  
  819. void PanelEditor::InternalizeStateInfo(    Environment*        ev,
  820.                                          ODStorageUnit*        storageUnit )
  821. {
  822.     SOM_Trace("PanelEditor","InternalizeStateInfo");
  823.  
  824.     ODStorageUnitRef    weakRef;
  825.     ODULong                size;
  826.  
  827.     // Internalize the part's display frame list.
  828.  
  829.     if ( storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) )
  830.     {
  831.         storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined,
  832.                                     kODWeakStorageUnitRefs, 0, kODPosUndefined);
  833.                                     
  834.         size = storageUnit->GetSize(ev);
  835.         storageUnit->SetOffset(ev, 0);    
  836.     
  837.         for ( ODULong offset = 0; offset < size; offset += kODStorageUnitRefSize )
  838.         {    
  839.             TRY    
  840.                 StorageUnitGetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef);
  841.                 
  842.                 if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) )
  843.                 {        
  844.                     // We lazily internalize our display frames, meaning we don't "get"
  845.                     // the frame until we absolutely need it. This reduces the time
  846.                     // to internalize the part and the amount of memory needed.
  847.                     
  848.                     // Convert the reference into a runtime id.
  849.                     ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef);
  850.  
  851.                     // Create a proxy class to support the lazy internalization.
  852.                     CFrameProxy* proxy = new CFrameProxy;
  853.                     proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit));
  854.  
  855.                     // Add the proxy to the display frame collection.
  856.                     fDisplayFrames->Add(proxy);
  857.                 }
  858.             CATCH_ALL
  859.                 // consume exception
  860.             ENDTRY
  861.         }
  862.     }
  863. }
  864.  
  865. //------------------------------------------------------------------------------
  866. // Method:        InternalizeContent
  867. // Origin:        Panel Editor
  868. //
  869. // Description:    This method is called during initialization of the part from an
  870. //                existing document. The content of the part should be read in.
  871. //
  872. //                The part has no intrinsic content, so the part does nothing.
  873. //                The method is here for completeness.
  874. //------------------------------------------------------------------------------
  875.  
  876. void PanelEditor::InternalizeContent( Environment*        ev,
  877.                                       ODStorageUnit*    storageUnit )
  878. {
  879.     SOM_Trace("PanelEditor","InternalizeContent");
  880.     
  881.     if ( storageUnit->Exists(ev, kODPropContents, kPanelEditorKind, 0) )
  882.     {
  883.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined,
  884.                                 kPanelEditorKind, 0, kODPosUndefined);
  885.         
  886.         // Get the number of embedded items we wrote out last time.
  887.         
  888.         ODULong count = 0;
  889.         
  890.         StorageUnitGetValue(storageUnit, ev, sizeof(ODULong), (ODPtr)&count);
  891.         
  892.         for (ODULong i=1; i<=count; i++)
  893.         {
  894.             // Create our handler class for embedded frames and
  895.             // ask it to read its state back in.
  896.             CListItem* item = new CListItem;
  897.             item->InitListItem();
  898.             item->Read(ev, storageUnit);
  899.             
  900.             // Add the resurrected item to our list.
  901.             fEmbeddedParts->AddLast((ODPtr)item);
  902.         }
  903.     }
  904. }
  905.  
  906. //------------------------------------------------------------------------------
  907. // Method:        CloneInto
  908. // Origin:        ODPart
  909. //
  910. // Description:    This method is called during cloning, typically during data
  911. //                interchange operations (ie. Cut/Paste). The part should
  912. //                write out its current state and content.
  913. //
  914. // Parent:        The part's parent class was called before this method was
  915. //                dispatched to (see som_SamplePart.cpp).
  916. //------------------------------------------------------------------------------
  917.  
  918. void PanelEditor::CloneInto( Environment*        ev,
  919.                             ODDraftKey            key,
  920.                             ODStorageUnit*        destinationSU,
  921.                             ODFrame*            initiatingFrame )
  922. {
  923.     SOM_Trace("PanelEditor","CloneInto");
  924.     
  925.     // We must first verify that we've never written to this storage unit.
  926.     // If we have, we should do nothing, otherwise we need to write out
  927.     // the current state of the part content.
  928.     
  929.     if ( destinationSU->Exists(ev, kODPropContents, kPanelEditorKind, 0) == kODFalse )
  930.     {
  931.         // Add the properties we need to successfully externalize
  932.         // ourselves into the destination storage unit.
  933.         this->CheckAndAddProperties(ev, destinationSU);
  934.                 
  935.         // Write out the part's state information.
  936.         this->ExternalizeStateInfo(ev, destinationSU, key, initiatingFrame);
  937.             
  938.         // Write out the part's content.
  939.         this->ExternalizeContent(ev, destinationSU, key, initiatingFrame);
  940.     }
  941.  
  942.     // Printing: Externalize the page setup info. It might be dirty even 
  943.     // if fDirty is false, so don't put this in the if block above.
  944.     if ( !fReadOnlyStorage && fPrinter ) 
  945.     {
  946.         TRY
  947.             fPrinter->Externalize(ev);
  948.         CATCH_ALL
  949.             WARN("Err %d externalizing page setup",ErrorCode());
  950.         ENDTRY
  951.     }
  952. }
  953.  
  954. //------------------------------------------------------------------------------
  955. // Method:        Externalize
  956. // Origin:        ODPart
  957. //
  958. // Description:    This method is called when the user saves the document. The part
  959. //                should write out its state and content if changes have occurred
  960. //                and if our storage is writeable.
  961. //
  962. // Parent:        The part's parent class was called before this method was
  963. //                dispatched to (see som_SamplePart.cpp).
  964. //------------------------------------------------------------------------------
  965.  
  966. void PanelEditor::Externalize( Environment* ev )
  967. {
  968.     SOM_Trace("PanelEditor","Externalize");
  969.  
  970.     TRY
  971.         if ( fDirty && !fReadOnlyStorage)
  972.         {
  973.             // Get our storage unit.
  974.             ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  975.     
  976.             // Verify that the storage unit has the appropriate properties
  977.             // and values to allow us to run. If not, add them.
  978.             this->CheckAndAddProperties(ev, storageUnit);
  979.         
  980.             // Verify that there are no "bogus" values in the Content
  981.             // property.
  982.             this->CleanseContentProperty(ev, storageUnit);
  983.         
  984.             // Write out the part's state information.
  985.             this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL);
  986.                 
  987.             // Write out the part's content.
  988.             this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  989.     
  990.             // Flag our part as no longer being dirty.
  991.             fDirty = kODFalse;
  992.         }
  993.  
  994.         // Printing: Externalize the page setup info. It might be dirty even 
  995.         // if fDirty is false, so don't put this in the if block above.
  996.         if ( !fReadOnlyStorage && fPrinter ) 
  997.         {
  998.             TRY
  999.                 fPrinter->Externalize(ev);
  1000.             CATCH_ALL
  1001.                 WARN("Err %d externalizing page setup",ErrorCode());
  1002.             ENDTRY
  1003.         }
  1004.  
  1005.     CATCH_ALL
  1006.         // Alert the user of the problem.
  1007.         this->DoDialogBox(ev, kODNULL, kErrorBoxID, kErrExternalizeFailed);
  1008.         // Change the exception value, so the DocShell doesn't display an
  1009.         // error dialog.
  1010.         SetErrorCode(kODErrAlreadyNotified);
  1011.         // Alert the caller.
  1012.         RERAISE;
  1013.     ENDTRY
  1014. }
  1015.  
  1016. //------------------------------------------------------------------------------
  1017. // Method:        ExternalizeKinds
  1018. // Origin:        ODPart
  1019. //
  1020. // Description:    This method is called when the user wants to save the document
  1021. //                with multiple representations of the data. This is especially
  1022. //                useful for increasing the portability of documents
  1023. //                cross-platform.
  1024. //
  1025. //                A part should verify each kind is valid, that it exists in
  1026. //                the content property in the correct order, and write the data.
  1027. //
  1028. // Note:        For parts which support only on kind, the code can simplified.
  1029. //                In this case, it is not necessary to iterate over the kindset
  1030. //                because you must, at least, write your preferred kind. The code
  1031. //                is shown this way to better illustrate the recipe; it is not
  1032. //                wrong, it just does more than it needs to.
  1033. //------------------------------------------------------------------------------
  1034.  
  1035. void PanelEditor::ExternalizeKinds(Environment* ev, ODTypeList* kindset)
  1036. {
  1037.     SOM_Trace("PanelEditor","ExternalizeKinds");
  1038.  
  1039.     if ( !fReadOnlyStorage )
  1040.     {
  1041.         ODBoolean preferredKindWritten = kODFalse;
  1042.         
  1043.         // Get our storage unit.
  1044.         ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  1045.         
  1046.         // Verify that the storage unit has the appropriate properties
  1047.         // and values to allow us to run. If not, add them.
  1048.         this->CheckAndAddProperties(ev, storageUnit);
  1049.     
  1050.         // Verify that there are no "bogus" values in the Content
  1051.         // property.
  1052.         this->CleanseContentProperty(ev, storageUnit);
  1053.     
  1054.         // Iterate over the kindset and write out the content types
  1055.         // that we support.
  1056.         TempODTypeListIterator tliter(ev, kindset);
  1057.         for ( ODType kind = tliter.First(); tliter.IsNotComplete();
  1058.                 kind = tliter.Next() )
  1059.         {
  1060.             // Check to see if this is a kind we support. If so, write it.
  1061.             if ( ODISOStrCompare(kind, kPanelEditorKind) == 0 )
  1062.             {
  1063.                 // Write out the part's content.
  1064.                 this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  1065.                 // This is our preferrend kind so we don't need to write it again.
  1066.                 // Part editors with more than one kind need to test each kind
  1067.                 // against the preferred kind to make sure it's been written.
  1068.                 preferredKindWritten = kODTrue;
  1069.             }
  1070.         }
  1071.     
  1072.         // Write out the part's state information.
  1073.         this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL);
  1074.  
  1075.         // Printing: Externalize the page setup info. It might be dirty even 
  1076.         // if fDirty is false, so don't put this in the if block above.
  1077.         if ( !fReadOnlyStorage && fPrinter ) 
  1078.         {
  1079.             TRY
  1080.                 fPrinter->Externalize(ev);
  1081.             CATCH_ALL
  1082.                 WARN("Err %d externalizing page setup",ErrorCode());
  1083.             ENDTRY
  1084.         }
  1085.  
  1086.         // Even if the kind set contains no types we support, we must at least
  1087.         // write out our current "preferred" kind.
  1088.         if ( preferredKindWritten == kODFalse )
  1089.         {
  1090.             // Write out the part's preferred content kind, which, for PanelEditor,
  1091.             // is the only kind.
  1092.             this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  1093.         }
  1094.     }
  1095. }
  1096.  
  1097. //------------------------------------------------------------------------------
  1098. // Method:        ChangeKind
  1099. // Origin:        ODPart
  1100. //
  1101. // Description:    This method is called when the changes the part's primary kind
  1102. //                and/or when the part editor is switched via the Info dialog.
  1103. //
  1104. //                The editor should record the new "preferred" kind and change the
  1105. //                UI, if necessary, to allow editing that kind. Don't write the
  1106. //                properties/values/data until the Externalize is called.
  1107. //------------------------------------------------------------------------------
  1108.  
  1109. void PanelEditor::ChangeKind(Environment* ev, ODType kind)
  1110. {
  1111.     if ( ODISOStrCompare(kind, kPanelEditorKind) != 0 )
  1112.         THROW(kODErrInvalidValueType);
  1113.         
  1114.     // Panel Editor only has one kind, so we do nothing.
  1115. }
  1116.  
  1117. //------------------------------------------------------------------------------
  1118. // Method:        ExternalizeStateInfo
  1119. // Origin:        Panel Editor
  1120. //
  1121. // Description:    This method is called during externalization of the part. The
  1122. //                current "state" of the part should be written out. This "state"
  1123. //                information may be lost during Data Interchange operations, so
  1124. //                the part needs to recover gracefully if information is missing
  1125. //                or incomplete.
  1126. //
  1127. // Note:        The function StorageUnitSetValue is a macro which simplifies
  1128. //                the use of ODByteArrary, which is required by the StorageUnit
  1129. //                interface. Look in StorUtil.h/cpp for an example of using the
  1130. //                ODByteArray struct.
  1131. //------------------------------------------------------------------------------
  1132.  
  1133. void PanelEditor::ExternalizeStateInfo( Environment*        ev,
  1134.                                         ODStorageUnit*        storageUnit,
  1135.                                         ODDraftKey            key,
  1136.                                         ODFrame*            scopeFrame )
  1137. {
  1138.     SOM_Trace("PanelEditor","ExternalizeStateInfo");
  1139.  
  1140.     ODStorageUnitRef    weakRef;
  1141.     ODStorageUnitID        frameID;
  1142.     ODID                scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID );
  1143.     ODDraft*            fromDraft = ODGetDraft(ev,fSelf);
  1144.     
  1145.     // Externalize the part's display frame list.
  1146.  
  1147.     storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined,
  1148.                                 kODWeakStorageUnitRefs, 0, kODPosUndefined);
  1149.     
  1150.     // Persistent object references are stored in a side table, rather than
  1151.     // in the property/value stream. Thus, deleting the contents of a value
  1152.     // will not "delete" the references previously written to that value. To
  1153.     // completely "delete" all references written to the value, we must
  1154.     // remove the value and add it back.
  1155.     storageUnit->Remove(ev);
  1156.     storageUnit->AddValue(ev, kODWeakStorageUnitRefs);
  1157.  
  1158.     CListIterator fiter(fDisplayFrames);
  1159.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1160.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1161.     {
  1162.         // Get the ID of the frame we are going to weakly reference.
  1163.         frameID = proxy->GetID();
  1164.         
  1165.         // If a draft key exists, then we are being cloned to another draft.
  1166.         // We must "weak" clone our display frame and reference the cloned
  1167.         // frame. The part re-uses the frameID variable so there aren't two
  1168.         // different GetWeakStorageUnitRef calls.
  1169.         if ( key )
  1170.             frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID);
  1171.         
  1172.         // Write out weak references to each of the part's display frames.
  1173.         storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef);
  1174.         TRY
  1175.             StorageUnitSetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef);
  1176.         CATCH_ALL
  1177.             // consume the exception
  1178.         ENDTRY
  1179.     }
  1180. }
  1181.  
  1182. //------------------------------------------------------------------------------
  1183. // Method:        ExternalizeContent
  1184. // Origin:        Panel Editor
  1185. //
  1186. // Description:    This method is called during exteralization of the part. The
  1187. //                content of the part should be written out.
  1188. //
  1189. //                The part's content consists of references to the other parts
  1190. //                embedded in it. The list of embedded items is written here.
  1191. //------------------------------------------------------------------------------
  1192.  
  1193. void PanelEditor::ExternalizeContent( Environment*            ev,
  1194.                                           ODStorageUnit*        storageUnit,
  1195.                                         ODDraftKey            key,
  1196.                                         ODFrame*            scopeFrame )
  1197. {
  1198.     SOM_Trace("PanelEditor","ExternalizeContent");
  1199.  
  1200.     if ( storageUnit->Exists(ev, kODPropContents, kPanelEditorKind, 0) )
  1201.     {
  1202.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined,
  1203.                                 kPanelEditorKind, 0, kODPosUndefined);
  1204.         
  1205.         // If we have written the embedded frame refs out before and
  1206.         // things have changed, we need to clear out the old refs
  1207.         // before writing the new ones.
  1208.         if ( storageUnit->GetSize(ev) > sizeof(ODULong) )
  1209.         {
  1210.             storageUnit->Remove(ev);
  1211.             storageUnit->AddValue(ev, kPanelEditorKind);
  1212.         }
  1213.                 
  1214.         // Write the embedded frame count out.
  1215.         ODULong count = fEmbeddedParts->Count();
  1216.         
  1217.         StorageUnitSetValue(storageUnit, ev, sizeof(ODULong), (ODPtr)&count);
  1218.         
  1219.         // If the key is valid, we must pass the "source" draft to the
  1220.         // items so that they can clone themselves.
  1221.         ODDraft* draft = (key != kODNULLKey) ? ODGetDraft(ev,fSelf) : kODNULL;
  1222.         
  1223.         // Then write a strong reference to each of the embedded frames.
  1224.         COrdListIterator fiter(fEmbeddedParts);
  1225.         for ( CListItem* item = (CListItem*)fiter.First();
  1226.                 fiter.IsNotComplete();
  1227.                 item = (CListItem*)fiter.Next() )
  1228.         {
  1229.             item->Write(ev, storageUnit, draft, key);
  1230.         }
  1231.     }
  1232. }
  1233.  
  1234. //------------------------------------------------------------------------------
  1235. // Method:        CleanseContentProperty
  1236. // Origin:        Panel Editor
  1237. //
  1238. // Description:    This method is called during exteralization of the part so that
  1239. //                the part can remove any value in the content property
  1240. //                that it cannot "accurately" write to.
  1241. //
  1242. // Note:        "Additional" values will be added to a part's content property
  1243. //                during Drag & Drop operations.
  1244. //------------------------------------------------------------------------------
  1245.  
  1246. void PanelEditor::CleanseContentProperty( Environment*        ev,
  1247.                                          ODStorageUnit*        storageUnit )
  1248. {
  1249.     SOM_Trace("PanelEditor","CleanseContentProperty");
  1250.  
  1251.     ODULong numValues;
  1252.     ODULong index;
  1253.     
  1254.     storageUnit->Focus(ev, kODPropContents, kODPosUndefined, 
  1255.                             kODNULL, 0, kODPosAll);
  1256.     
  1257.     numValues = storageUnit->CountValues(ev);
  1258.     
  1259.     for (index = numValues; index >= 1; index--)
  1260.     {
  1261.         // Index from 1 to n through the values.
  1262.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined, 
  1263.                                 kODNULL, index, kODPosUndefined);
  1264.  
  1265.         // Get the ISO type name for the value. The temp object
  1266.         // will automatically delete the returned value when this
  1267.         // scope is exited.
  1268.         TempODValueType value = storageUnit->GetType(ev);
  1269.         
  1270.         // If the value type is not one we support, remove it.
  1271.         if ( ODISOStrCompare(value, kPanelEditorKind) != 0 )
  1272.             storageUnit->Remove(ev);
  1273.     }
  1274. }
  1275.  
  1276. //------------------------------------------------------------------------------
  1277. // Method:        CheckAndAddProperties
  1278. // Origin:        Panel Editor
  1279. //
  1280. // Description:    This method is called during externalization of the part to
  1281. //                verify that all the properties needed to persistently represent
  1282. //                the current running state of the part.
  1283. //
  1284. //                The part adds the default content property, a preferred editor
  1285. //                property (to aid in part binding), and a display frames
  1286. //                property.
  1287. //
  1288. // Note:        The function StorageUnitSetValue is a macro which simplifies
  1289. //                the use of ODByteArrary, which is required the StorageUnit
  1290. //                interface. Look in StorUtil.h/cpp for an example of using the
  1291. //                ODByteArray struct.
  1292. //------------------------------------------------------------------------------
  1293.  
  1294. void PanelEditor::CheckAndAddProperties( Environment*    ev,
  1295.                                         ODStorageUnit*    storageUnit )
  1296. {
  1297.     SOM_Trace("PanelEditor","CheckAndAddProperties");
  1298.  
  1299.     // Create our content property and preferred content property kind.
  1300.  
  1301.     if ( !storageUnit->Exists(ev, kODPropContents, kODNULL, 0) )
  1302.         storageUnit->AddProperty(ev, kODPropContents);
  1303.     if ( !storageUnit->Exists(ev, kODPropContents, kPanelEditorKind, 0) )
  1304.     {    
  1305.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll);
  1306.         storageUnit->AddValue(ev, kPanelEditorKind);
  1307.     }
  1308.  
  1309.     // Since we are setting up the preferred kind property, we just write
  1310.     // out our default "kind" for the editor. We can write out the user
  1311.     // chosen kind in the ExternalizeStateInfo method.
  1312.  
  1313.     if ( !storageUnit->Exists(ev, kODPropPreferredKind, kODISOStr, 0) )
  1314.     {
  1315.         TRY
  1316.             ODSetISOStrProp(ev, storageUnit, kODPropPreferredKind, kODISOStr, kPanelEditorKind);
  1317.         CATCH_ALL
  1318.             // Remove the property and value if something went wrong.
  1319.             ODSURemoveProperty(ev, storageUnit, kODPropPreferredKind);
  1320.         ENDTRY
  1321.     }
  1322.     
  1323.     // Add our display frame list.
  1324.     
  1325.     if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODNULL, 0) )
  1326.         storageUnit->AddProperty(ev, kODPropDisplayFrames);
  1327.     if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) )
  1328.     {
  1329.         storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined, kODNULL, 0, kODPosAll);
  1330.         storageUnit->AddValue(ev, kODWeakStorageUnitRefs);
  1331.     }
  1332. }
  1333.  
  1334. //------------------------------------------------------------------------------
  1335. // Method:        SetDirty
  1336. // Origin:        Panel Editor
  1337. //
  1338. // Description:    This method is called by the part when the content or state of
  1339. //                the part has been modified by the user and the "Save" menu item
  1340. //                should be enabled.
  1341. //------------------------------------------------------------------------------
  1342.  
  1343. void PanelEditor::SetDirty( Environment*    ev )
  1344. {
  1345.     SOM_Trace("PanelEditor","SetDirty");
  1346.  
  1347.     // There is no need to repeatedly tell the draft we have changed;
  1348.     // once is sufficient.
  1349.     if ( !fDirty && !fReadOnlyStorage )
  1350.     {
  1351.         fDirty = kODTrue;
  1352.         ODGetDraft(ev,fSelf)->SetChangedFromPrev(ev);
  1353.     }
  1354. }
  1355.  
  1356. //------------------------------------------------------------------------------
  1357. // Method:        ReadPartInfo
  1358. // Origin:        ODPart
  1359. //
  1360. // Description:    When a frame is being internalized by the Draft, it will ask the
  1361. //                owner (part) to read in its info annotation on the frame.
  1362. //
  1363. //                The part uses a C++ helper class to encapsulate the information
  1364. //                we store with each frame, so we let it internalize itself from
  1365. //                the storage unit view.
  1366. //------------------------------------------------------------------------------
  1367.  
  1368. ODInfoType PanelEditor::ReadPartInfo(    Environment*        ev,
  1369.                                         ODFrame*            frame,
  1370.                                         ODStorageUnitView*    storageUnitView )
  1371. {
  1372.     SOM_Trace("PanelEditor","ReadPartInfo");
  1373.  
  1374.     CFrameInfo* frameInfo = kODNULL;
  1375.         
  1376.     TRY
  1377.         frameInfo = new CFrameInfo(ODGetSession(ev,fSelf));
  1378.         frameInfo->InitFromStorage(ev, storageUnitView);
  1379.     CATCH_ALL
  1380.         // Clean up the allocated memory.
  1381.         ODDeleteObject(frameInfo);
  1382.         // Alert the caller.
  1383.         RERAISE;
  1384.     ENDTRY
  1385.     
  1386.     return (ODInfoType)frameInfo;
  1387. }
  1388.  
  1389. //------------------------------------------------------------------------------
  1390. // Method:        WritePartInfo
  1391. // Origin:        ODPart
  1392. //
  1393. // Description:    When a frame is being externalized by the Draft, it will ask the
  1394. //                owner (part) to write out its info annotation on the frame.
  1395. //
  1396. //                The part uses a C++ helper class to encapsulate the information
  1397. //                we store with each frame, so we let it externalize itself to
  1398. //                the storage unit view.
  1399. //------------------------------------------------------------------------------
  1400.  
  1401. void PanelEditor::WritePartInfo(    Environment*        ev,
  1402.                                       ODInfoType            partInfo,
  1403.                                     ODStorageUnitView*    storageUnitView )
  1404. {
  1405.     SOM_Trace("PanelEditor","WritePartInfo");
  1406.  
  1407.     // Tell our frame info class to write itself out to the prefocused
  1408.     // storage unit.
  1409.     ((CFrameInfo*) partInfo)->Externalize(ev, storageUnitView);
  1410. }
  1411.  
  1412. //------------------------------------------------------------------------------
  1413. // Method:        ClonePartInfo
  1414. // Origin:        ODPart
  1415. //
  1416. // Description:    When a frame is being cloned by the Draft, it will ask the owner
  1417. //                (part) to clone its info annotation on the frame.
  1418. //
  1419. //                The part uses a C++ helper class to encapsulate the information
  1420. //                we store with each frame, so we let it clone itself to the
  1421. //                storage unit view.
  1422. //------------------------------------------------------------------------------
  1423.  
  1424. void PanelEditor::ClonePartInfo( Environment*        ev,
  1425.                                 ODDraftKey            key,
  1426.                                   ODInfoType            partInfo,
  1427.                                 ODStorageUnitView*    storageUnitView,
  1428.                                 ODFrame*            scopeFrame )
  1429. {
  1430.     SOM_Trace("PanelEditor","ClonePartInfo");
  1431.  
  1432.     // Tell our frame info class to write itself out into the pre-
  1433.     // focused storage unit.
  1434.     ((CFrameInfo*) partInfo)->CloneInto(ev, key, storageUnitView, scopeFrame);
  1435. }
  1436.  
  1437. //==============================================================================
  1438. #pragma mark    • Layout •
  1439. //==============================================================================
  1440.  
  1441. //------------------------------------------------------------------------------
  1442. // Method:        DisplayFrameAdded
  1443. // Origin:        ODPart
  1444. //
  1445. // Description:    This method is called in response to a frame being created for
  1446. //                the part.
  1447. //
  1448. //                The part records the existence of a new display frame in its
  1449. //                internal display frame list, as well as, verify that the frame
  1450. //                is "set up" correctly (i.e., valid viewType). The part also
  1451. //                creates and stores its "frame info" class in the new frame. 
  1452. //------------------------------------------------------------------------------
  1453.  
  1454. void PanelEditor::DisplayFrameAdded( Environment* ev, ODFrame* frame )
  1455. {
  1456.     SOM_Trace("PanelEditor","DisplayFrameAdded");
  1457.  
  1458.     // If we are being embedded into another part, the presentation field
  1459.     // will be NULL or undefined; we need to set it something meaningful.
  1460.     // The view field may also be null, if so, we prefer to be displayed
  1461.     // in a frame view.
  1462.  
  1463.     if ( frame->GetPresentation(ev) == kODNullTypeToken ||
  1464.             frame->GetPresentation(ev) == gGlobals->fUndefinedPresentation )
  1465.         frame->SetPresentation(ev, gGlobals->fMainPresentation);
  1466.     
  1467.     if ( frame->GetViewType(ev) == kODNullTypeToken )
  1468.         frame->SetViewType(ev, gGlobals->fFrameView);
  1469.         
  1470.     // Hang our "state" info off of the new display frame. We use
  1471.     // the CFrameInfo object for activation, updating, and window
  1472.     // maintenance.
  1473.     CFrameInfo* frameInfo = new CFrameInfo(ODGetSession(ev,fSelf));
  1474.     frame->SetPartInfo(ev, (ODInfoType)frameInfo);
  1475.         
  1476.     // If the frame being added is a root frame, we know that a window
  1477.     // is associated with this frame. Notify ourselves that we need to 
  1478.     // clean it up when the frame goes away.
  1479.     if ( frame->IsRoot(ev) )
  1480.         frameInfo->SetShouldDisposeWindow(kODTrue);
  1481.     
  1482.     // The proxy class will refcount the frame passed to it, so we
  1483.     // don't need to worry about refcounting the display frame.
  1484.     CFrameProxy* proxy = new CFrameProxy;
  1485.     proxy->InitFrameProxy(ev,frame);
  1486.  
  1487.     // Add the proxy to the display frame collection.
  1488.     fDisplayFrames->Add(proxy);
  1489.  
  1490.     // Since we maintain a persistent list of weak references to our
  1491.     // display frames, having one added to the part dirties it.
  1492.     this->SetDirty(ev);
  1493.  
  1494.     // If the frame's presentation is "main", we need to create a list
  1495.     // and panel frame inside of it.
  1496.     if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  1497.     {
  1498.         // Ask the list proxy to create a frame inside the root frame.
  1499.         fList->SetPartDisplayed(ev, fSelf);
  1500.         fList->AddFrame(ev, frame);
  1501.  
  1502.         // Ask the panel proxy to create a frame inside the root frame.
  1503.         fPanel->AddFrame(ev, frame);
  1504.         
  1505.         // Negotiate for more frame space?
  1506.         if ( !frame->IsRoot(ev) )
  1507.         {
  1508.             ODRect bounds;
  1509.             TempODShape frameShape = frame->AcquireFrameShape(ev,kODNULL);
  1510.             frameShape->GetBoundingBox(ev, &bounds);
  1511.             
  1512.             // If the frame we've been given is too small, remember to request a larger
  1513.             // frame shape in FacetAdded().
  1514.             if ( FixedToInt(bounds.Height()) < this->GetMinHeight() ||
  1515.                     FixedToInt(bounds.Width()) < this->GetMinWidth() )
  1516.             {
  1517.                 frameInfo->SetShouldNegotiate(kODTrue);
  1518.             }
  1519.         }
  1520.     }
  1521. }
  1522.  
  1523. //------------------------------------------------------------------------------
  1524. // Method:        DisplayFrameConnected
  1525. // Origin:        ODPart
  1526. //
  1527. // Description:    This method is called when one of our display frames, previously
  1528. //                written out, is internalized. This method is called instead of
  1529. //                DisplayFrameAdded because a "new" frame is not being created;
  1530. //                an existing one is being reconstituted.
  1531. //
  1532. //                The part first checks to see if we can match its frame to an
  1533. //                ID in the Display frame list; if so, we put the frame into the
  1534. //                proxy. For frames we do not recognize, just add them.
  1535. //
  1536. // Warning:        This method may be calle,d during editor swapping, with a frame
  1537. //                not recognized by the part. This is ok. Just treat the case as
  1538. //                if a "new" frame were being added to the part.
  1539. //------------------------------------------------------------------------------
  1540.  
  1541. void PanelEditor::DisplayFrameConnected(    Environment*    ev,
  1542.                                             ODFrame*        frame )
  1543. {
  1544.     SOM_Trace("PanelEditor","DisplayFrameConnected");
  1545.     
  1546.     // Iterate over our display collection to match the frame with
  1547.     // an existing proxy with the correct frame ID. If we find it,
  1548.     // replace the ID with the actual frame. If we don't find it,
  1549.     // signal an error.
  1550.     ODBoolean found = kODFalse;
  1551.     CListIterator fiter(fDisplayFrames);
  1552.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1553.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1554.     {
  1555.         if ( proxy->GetID() == frame->GetID(ev) )
  1556.         {
  1557.             // The proxy class will refcount the frame passed to it, so we
  1558.             // don't need to worry about refcounting the display frame.
  1559.             proxy->SetFrame(ev,frame);
  1560.             found = kODTrue;
  1561.         }
  1562.     }
  1563.  
  1564.     // Parts typically operate under the assumption that they have previous
  1565.     // knowledge of a frame before it is connected to it. This knowledge
  1566.     // should come from having read in the frame reference when the part
  1567.     // was internalized. If the frame is an "unknown", the part was probably
  1568.     // bound to another editors storage unit because the editor is missing or
  1569.     // the user changed the editor in the Info dialog. 
  1570.     if ( found )
  1571.     {
  1572.         // Now that we know we are operating on a valid frame, prepare it
  1573.         // based on the presentation it displays.
  1574.         if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  1575.         {
  1576.             // If the frame being added is a root frame, we know that a window
  1577.             // is associated with this frame. Notify ourselves that we need to 
  1578.             // clean it up when the frame goes away.
  1579.             if ( frame->IsRoot(ev) )
  1580.             {
  1581.                 CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1582.                 frameInfo->SetShouldDisposeWindow(kODTrue);
  1583.             }
  1584.             
  1585.             // Register the root frame with the panel frame proxy object.
  1586.             fList->SetPartDisplayed(ev, fSelf);
  1587.             fList->AddFrame(ev, frame);
  1588.             
  1589.             // Register the root frame with the panel frame proxy object.
  1590.             fPanel->AddFrame(ev, frame);
  1591.         }
  1592.     }
  1593.     else
  1594.     {
  1595.         // If an unrecognizable frame is connected to us, treat it like a "new"
  1596.         // frame and call our method to add it.
  1597.         this->DisplayFrameAdded(ev, frame);
  1598.     }
  1599. }
  1600.  
  1601. //------------------------------------------------------------------------------
  1602. // Method:        DisplayFrameRemoved
  1603. //
  1604. // Description:    This method is called in response to a frame being removed from
  1605. //                the part.
  1606. //
  1607. //                The part removes the frame from its internal display frame list
  1608. //                and reliquishes any foci that it still owned. Lastly, if the
  1609. //                frame has a source frame (it was the root frame of a part
  1610. //                window), we will record the part window bounds so that any
  1611. //                subsequent part windows opened on the source frame will appear
  1612. //                in the same location.
  1613. //------------------------------------------------------------------------------
  1614.  
  1615. void PanelEditor::DisplayFrameRemoved(    Environment*    ev,
  1616.                                          ODFrame*        frame )
  1617. {
  1618.     SOM_Trace("PanelEditor","DisplayFrameRemoved");
  1619.  
  1620.     TRY
  1621.         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1622.     
  1623.         // Make sure the frame going away does not own any foci. Forgetting
  1624.         // to do this, will cause a "refcounting" error when the frame
  1625.         // is deleted by the draft.
  1626.         this->RelinquishAllFoci(ev, frame);
  1627.     
  1628.         // If removing a child window, show zoom rects back to source.
  1629.         // NOTE: This has to be done before CleanupDisplayFrame because 
  1630.         // CleanupDisplayFrame will remove the relationship.
  1631.         if ( frame->IsRoot(ev) && frameInfo->HasSourceFrame() )
  1632.         {
  1633.             TempODWindow window = frame->AcquireWindow(ev);
  1634.             this->ZoomPartWindow(ev, frameInfo->GetSourceFrame(ev),
  1635.                                     window, kWindowClosing);
  1636.         }
  1637.                 
  1638.         // Clean up the embedded frames; both ours and other parts.
  1639.         this->CleanupEmbeddedFrames(ev, frame, kFrameRemoved);
  1640.         // Clean up the display frame.
  1641.         this->CleanupDisplayFrame(ev, frame, kFrameRemoved);
  1642.         // Clean up any associated window.
  1643.         this->CleanupWindow(ev, frame);
  1644.         // Dispose of the frame's runtime state info.
  1645.         frame->SetPartInfo(ev, (ODInfoType) kODNULL);
  1646.         ODDeleteObject(frameInfo);
  1647.         
  1648.         // Remove the display frame from our collection.
  1649.         CListIterator fiter(fDisplayFrames);
  1650.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1651.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1652.         {
  1653.             if ( ODObjectsAreEqual(ev, proxy->GetFrame(ev), frame) )
  1654.             {
  1655.                 // Delete the proxy object and its contents. The frame's
  1656.                 // refcount will be decremented in the proxy destructor.
  1657.                 fiter.RemoveCurrent();
  1658.                 delete proxy;
  1659.             }
  1660.         }
  1661.  
  1662.         // Since we maintain a persistent list of weak references to our
  1663.         // display frames, having one removed from the part dirties it.
  1664.         this->SetDirty(ev);
  1665.     
  1666.     CATCH_ALL
  1667.         // Alert the user of the problem.
  1668.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
  1669.         // Change the exception value, so the DocShell doesn't display an
  1670.         // error dialog.
  1671.         SetErrorCode(kODErrAlreadyNotified);
  1672.         // Alert the caller.
  1673.         RERAISE;
  1674.     ENDTRY
  1675. }
  1676.  
  1677. //------------------------------------------------------------------------------
  1678. // Method:        DisplayFrameClosed
  1679. //
  1680. // Description:    This method is called in response to a frame being closed as a
  1681. //                result of the document having been closed by the user.
  1682. //
  1683. //                The part behaves much the same way that it would if a frame were
  1684. //                removed (see above), except that we don't need to cache runtime
  1685. //                information. 
  1686. //------------------------------------------------------------------------------
  1687.  
  1688. void PanelEditor::DisplayFrameClosed(    Environment*    ev,
  1689.                                         ODFrame*        frame )
  1690. {
  1691.     SOM_Trace("PanelEditor","DisplayFrameClosed");
  1692.  
  1693.     TRY
  1694.         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1695.     
  1696.         // Make sure the frame going away does not own any foci. Forgetting
  1697.         // to do this, will cause a "refcounting" error when the frame
  1698.         // is deleted by the draft.
  1699.         this->RelinquishAllFoci(ev, frame);
  1700.  
  1701.         // Clean up the embedded frames; both ours and other parts.
  1702.         this->CleanupEmbeddedFrames(ev, frame, kFrameClosed);
  1703.         // Clean up the display frame.
  1704.         this->CleanupDisplayFrame(ev, frame, kFrameClosed);
  1705.         // Clean up any associated window.
  1706.         this->CleanupWindow(ev, frame);
  1707.         // Dispose of the frame's runtime state info.
  1708.         frame->SetPartInfo(ev, (ODInfoType) kODNULL);
  1709.         ODDeleteObject(frameInfo);
  1710.         
  1711.         // Remove the display frame from our collection.
  1712.         CListIterator fiter(fDisplayFrames);
  1713.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1714.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1715.         {
  1716.             if ( proxy->GetID() == frame->GetID(ev) )
  1717.             {
  1718.                 // Release the frame reference, but don't get rid of the
  1719.                 // proxy object because "closed" frames may be reconnected
  1720.                 // before the document is closed.
  1721.                 proxy->Purge(ev);
  1722.             }
  1723.         }
  1724.         
  1725.     CATCH_ALL
  1726.         // Alert the user of the problem.
  1727.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
  1728.         // Change the exception value, so the DocShell doesn't display an
  1729.         // error dialog.
  1730.         SetErrorCode(kODErrAlreadyNotified);
  1731.         // Alert the caller.
  1732.         RERAISE;
  1733.     ENDTRY
  1734. }
  1735.  
  1736. //------------------------------------------------------------------------------
  1737. // Method:        CleanupEmbeddedFrames
  1738. // Origin:        PanelEditor
  1739. //
  1740. // Description:    This method is called when a frame has been closed or removed.
  1741. //                The method cleans up the references and state information stored
  1742. //                in the CFrameInfo class.
  1743. //------------------------------------------------------------------------------
  1744.  
  1745. void PanelEditor::CleanupEmbeddedFrames(Environment*    ev,
  1746.                                         ODFrame*        frame,
  1747.                                         ODBoolean        frameRemoved )
  1748. {
  1749.     SOM_Trace("PanelEditor","CleanupEmbeddedFrames");
  1750.  
  1751.     ODError        error = noErr;
  1752.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1753.  
  1754.     TRY
  1755.         // Close the embedded frames, if this frame has any.
  1756.         if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  1757.         {
  1758.             if ( frameRemoved )
  1759.             {
  1760.                 // Ask the panel proxy to remove the frame embedded in this one.
  1761.                 fList->RemoveFrame(ev, frame);
  1762.     
  1763.                 // Ask the panel proxy to remove the frame embedded in this one.
  1764.                 fPanel->RemoveFrame(ev, frame);
  1765.             }
  1766.             else
  1767.             {
  1768.                 // Ask the panel proxy to close the frame embedded in this one.
  1769.                 fList->CloseFrame(ev, frame);
  1770.     
  1771.                 // Ask the panel proxy to close the frame embedded in this one.
  1772.                 fPanel->CloseFrame(ev, frame);
  1773.             }
  1774.         }
  1775.         else if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  1776.         {
  1777.             // Remove all the items from the selection.
  1778.             if ( fSelection )
  1779.                 fSelection->Empty(ev, kODFalse);
  1780.         }
  1781.     CATCH_ALL
  1782.     ENDTRY
  1783. }
  1784.  
  1785. //------------------------------------------------------------------------------
  1786. // Method:        CleanupDisplayFrame
  1787. // Origin:        PanelEditor
  1788. //
  1789. // Description:    This method is called when a frame has been closed or removed.
  1790. //                The method cleans up the references and state information stored
  1791. //                in the CFrameInfo class.
  1792. //------------------------------------------------------------------------------
  1793.  
  1794. void PanelEditor::CleanupDisplayFrame(    Environment*    ev,
  1795.                                         ODFrame*        frame,
  1796.                                         ODBoolean        frameRemoved )
  1797. {
  1798.     SOM_Trace("PanelEditor","CleanupDisplayFrame");
  1799.  
  1800.     ODError        error = noErr;
  1801.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1802.  
  1803.     TRY
  1804.         // If we are the root of a child window, we need to notify
  1805.         // our source frame that we are going away.
  1806.         if ( frameInfo->HasSourceFrame() )
  1807.         {
  1808.             ODFrame* sourceFrame = frameInfo->GetSourceFrame(ev);
  1809.             CFrameInfo* sourceFrameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
  1810.  
  1811.             if ( frameRemoved )
  1812.             {
  1813.                 // Invalidate the source frame. We do this because the
  1814.                 // source frame may have a unique display when it has
  1815.                 // been opened into a part window. This forces the
  1816.                 // frame to redraw "not opened".
  1817.                 sourceFrame->Invalidate(ev, kODNULL, kODNULL);
  1818.             }
  1819.             
  1820.             // Tell the source frame that its dependent is going away.
  1821.             sourceFrameInfo->ReleaseDependentFrame(ev);            
  1822.  
  1823.             // Release our reference to the source frame.
  1824.             frameInfo->ReleaseSourceFrame(ev);
  1825.  
  1826.             // If the frame is the root, it is a part window going away
  1827.             // and we need to notify our source frame that it no longer
  1828.             // has a part window.
  1829.             if ( frame->IsRoot(ev) )
  1830.                 sourceFrameInfo->SetPartWindow(ev, kODNULL);
  1831.         }
  1832.     CATCH_ALL
  1833.         error = ErrorCode();
  1834.     ENDTRY
  1835.     
  1836.     TRY
  1837.         // If the frame was removed from the document, we need to remove
  1838.         // any child window displaying that frame.
  1839.         if ( frameRemoved )
  1840.         {
  1841.             // If we have a child window, we need to close it.
  1842.             ODWindow* window = frameInfo->AcquirePartWindow(ev);
  1843.  
  1844.             if ( window )
  1845.             {
  1846.                 frameInfo->SetPartWindow(ev, kODNULL);
  1847.                 window->CloseAndRemove(ev);
  1848.             }
  1849.         }
  1850.     CATCH_ALL
  1851.         error = ErrorCode();
  1852.     ENDTRY
  1853.  
  1854.     TRY
  1855.         // If we have dependent frames, we need to notify them that we
  1856.         // are going away.
  1857.     
  1858.         if ( frameInfo->HasDependentFrame() )
  1859.         {
  1860.             // Get the frame that is dependent on this one. We can safely
  1861.             // do this because we only reference our own display frames.
  1862.             ODFrame* dependentFrame = frameInfo->GetDependentFrame(ev);
  1863.             CFrameInfo* dependentFrameInfo = (CFrameInfo*) dependentFrame->GetPartInfo(ev);
  1864.  
  1865.             // Tell the dependent frame that its source is going away.
  1866.             dependentFrameInfo->ReleaseSourceFrame(ev);
  1867.             
  1868.             // Release our reference to the dependent frame.
  1869.             frameInfo->ReleaseDependentFrame(ev);
  1870.         }
  1871.     CATCH_ALL
  1872.         error = ErrorCode();
  1873.     ENDTRY
  1874.     
  1875.     // If anything went wrong, signal an error.
  1876.     THROW_IF_ERROR(error);
  1877. }
  1878.  
  1879. //------------------------------------------------------------------------------
  1880. // Method:        AttachSourceFrame
  1881. // Origin:        ODPart
  1882. //
  1883. // Description:    If the part which we are contained in is opened into a part
  1884. //                window, it is required to iterate over its embedded frames and
  1885. //                add new display frames in the part window. After each new
  1886. //                embedded frame is created, this method will be called.
  1887. //
  1888. //                Given all that, and given our lack of interesting
  1889. //                content, we just validate the frame and attach it to its source.
  1890. //------------------------------------------------------------------------------
  1891.  
  1892. void PanelEditor::AttachSourceFrame(Environment*    ev,
  1893.                                     ODFrame*        frame,
  1894.                                     ODFrame*        sourceFrame )
  1895. {
  1896.     SOM_Trace("PanelEditor","AttachSourceFrame");
  1897.  
  1898.     // Tell the new frame about its source.
  1899.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1900.     frameInfo->SetSourceFrame(ev, sourceFrame);
  1901.     
  1902.     // And tell the source about its new dependent.
  1903.     frameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
  1904.     frameInfo->SetDependentFrame(ev, frame);
  1905.     
  1906.     // In both cases, refcounting of the frame and sourceFrame is
  1907.     // handled by the CFrameInfo class.
  1908.  
  1909.     if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  1910.     {
  1911.         // Ask the panel object to attach the appropriate frames.
  1912.         fList->AttachSourceFrame(ev, frame, sourceFrame);
  1913.  
  1914.         // Ask the panel object to attach the appropriate frames.
  1915.         fPanel->AttachSourceFrame(ev, frame, sourceFrame);
  1916.     }
  1917.     else if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  1918.     {
  1919.         // Instruct the list to attach embedded items to their sources.
  1920.         fList->SourceFrameAttached(ev,frame,sourceFrame);
  1921.     }
  1922. }
  1923.  
  1924. //------------------------------------------------------------------------------
  1925. // Method:        EmbedNewItem
  1926. // Origin:        PanelEditor
  1927. //
  1928. // Description:    This method is called by the Drop method to clone and embed an
  1929. //                interchange storageunit into the list.
  1930. //------------------------------------------------------------------------------
  1931.  
  1932. void PanelEditor::EmbedNewItem(    Environment*    ev, 
  1933.                                 ODFacet*        facet,
  1934.                                 ODID            partID)
  1935. {
  1936.     SOM_Trace("PanelEditor","EmbedNewItem");
  1937.     
  1938.     ODDraft*    draft = ODGetDraft(ev, fSelf);
  1939.     TempODPart    newPart = draft->AcquirePart(ev, partID);
  1940.     
  1941.     THROW_IF_NULL(newPart);
  1942.     
  1943.     // Ask the list to create embedded frames for the new part.
  1944.     CListItem* newItem = fList->EmbedPart(ev, newPart);
  1945.  
  1946.     TRY
  1947.         if ( newItem )
  1948.         {
  1949.             // Add the proxy to our embedded parts collection.
  1950.             fEmbeddedParts->AddLast((ODPtr)newItem);
  1951.             
  1952.             // The "dropped" item becomes the current selection
  1953.             fSelection->Add(ev, newItem);
  1954.             // Change the panel frame display to the newly selected item.
  1955.             fPanel->ChangeDisplayItem(ev, newItem);
  1956.         }
  1957.     
  1958.     CATCH_ALL
  1959.         fSelection->Empty(ev);
  1960.         if ( newItem ) newItem->Release(ev);
  1961.     ENDTRY
  1962. }
  1963.  
  1964. //------------------------------------------------------------------------------
  1965. // Method:        RemoveListItem
  1966. // Origin:        PanelEditor
  1967. //
  1968. // Description:    This method is called in
  1969. //------------------------------------------------------------------------------
  1970.  
  1971. void PanelEditor::RemoveListItem(Environment* ev, CListItem* item)
  1972. {
  1973.     SOM_Trace("PanelEditor","RemoveListItem");
  1974.  
  1975.     // Remove the item from our embedded parts collection.
  1976.     fEmbeddedParts->Remove((ODPtr)item);
  1977.     // Release the parts's reference to the item.
  1978.     item->Invalidate(ev);
  1979.     item->Release(ev);
  1980. }
  1981.  
  1982. //------------------------------------------------------------------------------
  1983. // Method:        ViewTypeChanged
  1984. // Origin:        ODPart
  1985. //
  1986. // Description:    This method is called in response to one of our display frame's
  1987. //                viewType field being modified. We call this method on ourselves
  1988. //                when new display frames are added, but it call also be called
  1989. //                when the user changes the view in the "part info" dialog.
  1990. //
  1991. //                The part first loads the appropriate view icons if needed and
  1992. //                then calculates a new "used" shape based on the bounds of the
  1993. //                new view type. If any problems occur while changing the view,
  1994. //                the part defaults back to frame view (the part's default view).
  1995. //------------------------------------------------------------------------------
  1996.  
  1997. void PanelEditor::ViewTypeChanged(    Environment*    ev,
  1998.                                      ODFrame*        frame )
  1999. {
  2000.     SOM_Trace("PanelEditor","ViewTypeChanged");
  2001.  
  2002.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2003.     
  2004.     ODTypeToken    view = frame->GetViewType(ev);
  2005.     ODTypeToken previousView = frameInfo->GetPreviousViewType();
  2006.     
  2007.     // If the view changes from frame to icon, or from icon to frame,
  2008.     // we must show/hide the embedded frames/content.
  2009.     
  2010.     if ( previousView == gGlobals->fFrameView &&
  2011.             view != gGlobals->fFrameView )
  2012.     {
  2013.         fList->RemoveFacets(ev, frame);
  2014.         fPanel->RemoveFacets(ev, frame);
  2015.     }
  2016.     else if ( previousView != gGlobals->fFrameView &&
  2017.             view == gGlobals->fFrameView )
  2018.     {
  2019.         fList->AddFacets(ev, frame);
  2020.         fPanel->AddFacets(ev, frame);
  2021.     }
  2022.     
  2023.     // Change this frame's used shape to match the new view setting.
  2024.     TempODShape newUsedShape = this->CalcNewUsedShape(ev, frame);    
  2025.  
  2026.     frame->Invalidate(ev, kODNULL, kODNULL);
  2027.     frame->ChangeUsedShape(ev, newUsedShape, kODNULL);
  2028.     frame->Invalidate(ev, kODNULL, kODNULL);
  2029.     
  2030.     // Remember the view we've just be set to.
  2031.     frameInfo->SetPreviousViewType(view);
  2032. }
  2033.  
  2034. //------------------------------------------------------------------------------
  2035. // Method:        CalcNewUsedShape
  2036. // Origin:        PanelEditor
  2037. //
  2038. // Description:    This method is called in response to one of display frame's view
  2039. //                being changed. The method calculates the appropriate usedShape
  2040. //                for the new view type.
  2041. //------------------------------------------------------------------------------
  2042.  
  2043. ODShape* PanelEditor::CalcNewUsedShape( Environment*    ev,
  2044.                                           ODFrame*        frame )
  2045. {
  2046.     SOM_Trace("PanelEditor","CalcNewUsedShape");
  2047.  
  2048.     ODShape*    usedShape    = kODNULL;
  2049.     ODTypeToken view        = frame->GetViewType(ev);
  2050.     
  2051.     ODVolatile(usedShape);
  2052.  
  2053.     // If the view is "frame", we intentionally return a nil shape;
  2054.     // doing so, will reset the used shape to equal the frame shape.
  2055.  
  2056.     if ( view == gGlobals->fLargeIconView ||
  2057.             view == gGlobals->fSmallIconView ||
  2058.             view == gGlobals->fThumbnailView )
  2059.     {
  2060.         TRY
  2061.             Rect        bounds;
  2062.             RgnHandle    usedRgn = ODNewRgn();
  2063.  
  2064.             if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView )
  2065.             {
  2066.                 // Focus to our library's resource fork so we can access our icons.
  2067.                 CUsingLibraryResources res;
  2068.  
  2069.                 // Set the bounds rect for the icon size.
  2070.                 SetRect(&bounds, 0, 0,
  2071.                         (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize,
  2072.                         (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize);
  2073.  
  2074.                 // Convert the icon mask into a Region.
  2075.                 OSErr error = IconIDToRgn(usedRgn, &bounds, atAbsoluteCenter, kBaseResourceID);
  2076.             }
  2077.             else if ( view == gGlobals->fThumbnailView )
  2078.             {    
  2079.                 PicHandle thumbnail = this->GenerateThumbnail(ev, frame);
  2080.  
  2081.                 if ( thumbnail )
  2082.                     bounds = (**thumbnail).picFrame;
  2083.                 else
  2084.                     SetRect(&bounds, 0, 0, kODThumbnailSize, kODThumbnailSize);
  2085.                     
  2086.                 RectRgn(usedRgn,&bounds);
  2087.             }
  2088.             
  2089.             usedShape = frame->CreateShape(ev);
  2090.             usedShape->SetQDRegion(ev, usedRgn);
  2091.                             
  2092.         CATCH_ALL
  2093.             ODSafeReleaseObject(usedShape);
  2094.         ENDTRY
  2095.     }
  2096.         
  2097.     return usedShape;
  2098. }
  2099.  
  2100. //------------------------------------------------------------------------------
  2101. // Method:        UpdateFrame
  2102. // Origin:        PanelEditor
  2103. //
  2104. // Description:    This method is called in response to one of our
  2105. //------------------------------------------------------------------------------
  2106.  
  2107. void
  2108. PanelEditor::UpdateFrame( Environment*    ev,
  2109.                          ODFrame*        frame,
  2110.                          ODTypeToken    view,
  2111.                          ODShape*        usedShape )
  2112. {
  2113.     SOM_Trace("PanelEditor","UpdateFrame");
  2114.  
  2115.     TRY
  2116.         // Update the frame to have the new view and UsedShape.
  2117.         frame->Invalidate(ev, kODNULL, kODNULL);
  2118.         frame->SetViewType(ev, view);
  2119.         frame->ChangeUsedShape(ev, usedShape, kODNULL);
  2120.         frame->Invalidate(ev, kODNULL, kODNULL);
  2121.     CATCH_ALL
  2122.         // Failing isn't great, but we can live with it, so don't set ev.
  2123.     ENDTRY
  2124. }
  2125.  
  2126. //------------------------------------------------------------------------------
  2127. // Method:        FrameShapeChanged
  2128. // Origin:        ODPart
  2129. //
  2130. // Description:    This method is called in response to a frame's shape being
  2131. //                altered, either by the user or the part we are embedded in.
  2132. //
  2133. //                To keep all attached frames in sync, we need to propogate the
  2134. //                new frame shape the frames dependent on the changed frame. This
  2135. //                is done by observing the display frames stored in the frame info
  2136. //                and calling RequestFrameShape for each.
  2137. //------------------------------------------------------------------------------
  2138.  
  2139. void PanelEditor::FrameShapeChanged( Environment* ev, ODFrame* frame )
  2140. {
  2141.     SOM_Trace("PanelEditor","FrameShapeChanged");
  2142.  
  2143.     // If the frame is the root frame of a part or document window, it should
  2144.     // have no effect on its attached frames or source frame.
  2145.  
  2146.     if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  2147.     {
  2148.         // We have strict size requirements, make sure our "new" frameshape
  2149.         // meets those requirements; if not, make changes.
  2150.         
  2151.         if ( !fNegotiating )
  2152.         {
  2153.             Rect box;
  2154.             GetQDFrameBounds(ev, frame, &box);
  2155.             
  2156.             ODSShort slop = (box.bottom-box.top-2*kListTopEdge) % kListItemHeight;
  2157.             if ( slop && slop < kListItemHeight/2 )
  2158.                 box.bottom -= slop;
  2159.             else if  ( slop )
  2160.                 box.bottom += (kListItemHeight-slop);
  2161.             
  2162.             if ( slop )
  2163.             {
  2164.                 if ( frame->IsRoot(ev) )
  2165.                 {
  2166.                     TempODWindow window = frame->AcquireWindow(ev);
  2167.                     THROW_IF_NULL(window);
  2168.                     ODPlatformWindow windowPtr = window->GetPlatformWindow(ev);
  2169.                     
  2170.                     ODSShort screenBottom = ODQDGlobals.screenBits.bounds.bottom;
  2171.                     ODSShort windowTop = (**(*(WindowPeek)windowPtr).contRgn).rgnBBox.top;
  2172.                     
  2173.                     while ( (windowTop + box.bottom) >= screenBottom )
  2174.                         box.bottom -= kListItemHeight;
  2175.                     
  2176.                     fNegotiating = kODTrue;
  2177.                     SizeWindow(windowPtr, box.right, box.bottom, kODTrue);
  2178.                     TRY
  2179.                         window->AdjustWindowShape(ev);
  2180.                     CATCH_ALL
  2181.                     ENDTRY
  2182.                     fNegotiating = kODFalse;
  2183.                 }
  2184.                 else
  2185.                 {
  2186.                     ODRect bounds(box);
  2187.                     TempODShape tShape = frame->CreateShape(ev);
  2188.                     tShape->SetRectangle(ev, &bounds);
  2189.                     
  2190.                     fNegotiating = kODTrue;
  2191.                     TRY
  2192.                         TempODShape rtnShape = frame->RequestFrameShape(ev, tShape, kODNULL);
  2193.                     CATCH_ALL
  2194.                     ENDTRY
  2195.                     fNegotiating = kODFalse;
  2196.                 }
  2197.             }
  2198.             
  2199.             // Resize the List and Panel frames.
  2200.             fList->Resize(ev, frame);
  2201.             fPanel->Resize(ev, frame);
  2202.             
  2203.             frame->Invalidate(ev, kODNULL, kODNULL);
  2204.         }
  2205.     }
  2206.  
  2207.     // Adjust the "used" shape for the new frame shape.
  2208.     TempODShape usedShape = this->CalcNewUsedShape(ev, frame);
  2209.     frame->ChangeUsedShape(ev, usedShape, kODNULL);
  2210. }
  2211.  
  2212. //------------------------------------------------------------------------------
  2213. // Method:        RequestFrameShape
  2214. // Origin:        ODPart
  2215. //
  2216. // Description:    This method is called when an embedded part wishes to negotiate
  2217. //                for a different frame shape. Since our view is static, we don't
  2218. //                allow embedded parts to change their frame shape. To prevent
  2219. //                part from changing its shape, we always return the "current"
  2220. //                frame shape.
  2221. //------------------------------------------------------------------------------
  2222.  
  2223. ODShape* PanelEditor::RequestFrameShape(Environment *ev,
  2224.                                         ODFrame* embeddedFrame,
  2225.                                         ODShape* /*frameShape*/)
  2226. {
  2227.     SOM_Trace("PanelEditor","RequestFrameShape");
  2228.  
  2229.     // We don't allow embedded items to resize themselves, so we just get the 
  2230.     // current frameShape and pass it back to the part.
  2231.  
  2232.     TempODShape frameShape = embeddedFrame->AcquireFrameShape(ev, kODNULL);
  2233.     return frameShape->Copy(ev);
  2234. }
  2235.  
  2236. //------------------------------------------------------------------------------
  2237. // Method:        Open
  2238. // Origin:        ODPart
  2239. //
  2240. // Description:    This method is called when OpenDoc, a containing part, or the
  2241. //                active editor would like to open a frame into a seperate window.
  2242. //                If a source frame is passed into this method, the editor is
  2243. //                being asked one of two things. If the frame is the root, we are
  2244. //                being asked to open an existing document. If the frame is not
  2245. //                the root, we are being asked to open a part window. If a source
  2246. //                frame is not specified, the editor is being asked to open a new
  2247. //                window.
  2248. //------------------------------------------------------------------------------
  2249.  
  2250. ODID PanelEditor::Open(    Environment*    ev,
  2251.                         ODFrame*        frame )
  2252. {
  2253.     SOM_Trace("PanelEditor","Open");
  2254.  
  2255.     ODID windowID;
  2256.     TempODWindow window(kODNULL);
  2257.  
  2258.     WindowProperties* windowProperties = kODNULL;
  2259.     ODVolatile(windowProperties);
  2260.  
  2261.     TRY
  2262.         // Because the frame parameter being passed to us can be one of
  2263.         // three things, we must determine what it is; either the root
  2264.         // frame of a existing document, the source frame for a part
  2265.         // window, or null if we are opening a new document.
  2266.     
  2267.         if ( frame == kODNULL )
  2268.         {
  2269.             // Calculate the bounding rectangle for a new window
  2270.             Rect windowRect = this->CalcPartWindowSize(ev, kODNULL);
  2271.             // Get the default setting for a document window.
  2272.             windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect);
  2273.             // Create a Mac Window and register it with OpenDoc.
  2274.             window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties);
  2275.         }
  2276.         else if ( frame->IsRoot(ev) )
  2277.         {
  2278.             // Get the previously saved settings for the document window.
  2279.             windowProperties = this->GetSavedWindowProperties(ev, frame);
  2280.             
  2281.             if ( windowProperties == kODNULL )
  2282.             {
  2283.                 // Calculate the bounding rectangle for a new window
  2284.                 Rect windowRect = this->CalcPartWindowSize(ev, frame);
  2285.                 // Get the default setting for a document window.
  2286.                 windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect);
  2287.             }
  2288.  
  2289.             // Create a Mac Window and register it with OpenDoc.
  2290.             window = this->CreateWindow(ev, frame, kODFrameObject, windowProperties);
  2291.             
  2292.             // We release the source frame here because we didn't call
  2293.             // EndGetWindowProperties and becuase we are done with it.
  2294.             ODReleaseObject(ev, windowProperties->sourceFrame);
  2295.         }
  2296.         else // frame is a source frame
  2297.         {
  2298.             window = this->AcquireFramesWindow(ev, frame);
  2299.     
  2300.             if ( window == kODNULL )
  2301.             {
  2302.                 // Calculate the bounding rectangle for a new window
  2303.                 Rect windowRect = this->CalcPartWindowSize(ev, frame);
  2304.                 // Get the default setting for a document window.
  2305.                 windowProperties = this->GetDefaultWindowProperties(ev, frame, &windowRect);
  2306.                 // Create a Mac Window and register it with OpenDoc.
  2307.                 window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties);
  2308.                 
  2309.                 // Tell the source frame that it is opened in a part window.
  2310.                 CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2311.                 frameInfo->SetPartWindow(ev, window);
  2312.     
  2313.                 this->ZoomPartWindow(ev, frame, window, kWindowOpening);
  2314.             }
  2315.         }
  2316.     
  2317.         // Creates the root facet for the window and notifies the
  2318.         // part.
  2319.         window->Open(ev);
  2320.         // Makes the window visible.
  2321.         window->Show(ev);
  2322.         // Activates and selects the window.
  2323.         window->Select(ev);
  2324.     
  2325.         // Cleanup allocate memory.
  2326.         ODDeleteObject(windowProperties);
  2327.         
  2328.         // Get window id to return.
  2329.         windowID = (window ? window->GetID(ev) : kODNULLID);
  2330.     
  2331.     CATCH_ALL
  2332.         // If we threw early, the source frame's refcount may be too high.
  2333.         if ( windowProperties )
  2334.             ODReleaseObject(ev, windowProperties->sourceFrame);
  2335.         // Cleanup the created items.
  2336.         ODDeleteObject(windowProperties);
  2337.         windowID = kODNULLID;
  2338.         // Alert the caller.
  2339.         RERAISE;
  2340.     ENDTRY
  2341.  
  2342.     return windowID;
  2343. }
  2344.  
  2345. //------------------------------------------------------------------------------
  2346. // Method:        AcquireFramesWindow
  2347. //
  2348. // Description:    This method is called by the part when a frame, that has been
  2349. //                previously opened, is being opened again.
  2350. //
  2351. //                The method retrieves the existing window for the frame and
  2352. //                returns it.                
  2353. //------------------------------------------------------------------------------
  2354.  
  2355. ODWindow* PanelEditor::AcquireFramesWindow( Environment*    ev,
  2356.                                                ODFrame*        frame )
  2357. {
  2358.     SOM_Trace("PanelEditor","AcquireFramesWindow");
  2359.  
  2360.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2361.     ODWindow* window = frameInfo->AcquirePartWindow(ev);
  2362.  
  2363.     return window;
  2364. }
  2365.     
  2366. //------------------------------------------------------------------------------
  2367. // Method:        CreateWindow
  2368. // Origin:        PanelEditor
  2369. //
  2370. // Description:    This method is called by the part when a window needs to be
  2371. //                created for a frame being opened.
  2372. //
  2373. //                The part uses the information passed in windowProperties to 
  2374. //                create the appropriate window. The generated window is
  2375. //                registered with OpenDoc as a new window (RegisterWindow) or as a
  2376. //                window from an existing document (RegisterWindowForFrame).
  2377. //------------------------------------------------------------------------------
  2378.  
  2379. ODWindow* PanelEditor::CreateWindow( Environment*         ev,
  2380.                                     ODFrame*            frame,
  2381.                                     ODType                frameType,
  2382.                                     WindowProperties*    windowProperties)
  2383. {
  2384.     SOM_Trace("PanelEditor","CreateWindow");
  2385.  
  2386.     ODPlatformWindow    platformWindow    = kODNULL; ODVolatile(platformWindow);
  2387.     ODWindow*            window            = kODNULL;
  2388.     
  2389.     // We force the "visible" flag for new and old windows so that we
  2390.     // always get an activate event when the window is displayed. This
  2391.     // is done to generate a consistent activation mechanism.
  2392.     windowProperties->wasVisible = kODFalse;
  2393.     
  2394.     // Using the name and the calculated rectangle, create a new window.
  2395.     platformWindow = NewCWindow((Ptr)ODNewPtr(sizeof(WindowRecord)),
  2396.                                 &(windowProperties->boundsRect),
  2397.                                 windowProperties->title,
  2398.                                 windowProperties->wasVisible,
  2399.                                 windowProperties->procID,
  2400.                                 (WindowPtr)-1L,
  2401.                                 windowProperties->hasCloseBox,
  2402.                                 windowProperties->refCon);
  2403.  
  2404.     if ( platformWindow )
  2405.     {
  2406.         TRY
  2407.             ODWindowState* windowState = ODGetSession(ev,fSelf)->GetWindowState(ev);
  2408.             
  2409.             // Shoud the window be saved in the document? Yes if the root frame is
  2410.             // persistent.
  2411.             ODBoolean saveWindow = (ODISOStrCompare(frameType,kODFrameObject) == 0);
  2412.             
  2413.             // Tell the window object that we will be disposing the window record
  2414.             // when the root frame is closed/removed.
  2415.             ODBoolean shouldDispose = kODFalse;
  2416.             
  2417.             // Determine whether we are creating a new window (frame is null),
  2418.             // or opening a previous saved window (frame is valid).
  2419.             
  2420.             if ( frame == kODNULL )
  2421.             {                                
  2422.                 // Tell OpenDoc about it by creating an OpenDoc window object.
  2423.                 window = windowState->
  2424.                             RegisterWindow(ev, 
  2425.                                 platformWindow,                    // Macintosh WindowPtr
  2426.                                 frameType,                        // Frame type (Persistent/Non-persistent)
  2427.                                 windowProperties->isRootWindow,    // Is this a document window?
  2428.                                 windowProperties->isResizable,    // Is this window resizeable?
  2429.                                 windowProperties->isFloating,    // Is this window floating?
  2430.                                 saveWindow,                        // Should this window be persistent?
  2431.                                 shouldDispose,                    // (see comment above)
  2432.                                 fSelf,                            // Part reference to us
  2433.                                 gGlobals->fFrameView,            // What view should the window have?
  2434.                                 gGlobals->fMainPresentation,    // What presentation should the window have?
  2435.                                 windowProperties->sourceFrame);    // The display frame being opened, if any
  2436.             }
  2437.             else
  2438.             {
  2439.                 // Tell OpenDoc about it by creating an OpenDoc window object.
  2440.                 window = windowState->
  2441.                             RegisterWindowForFrame(ev, 
  2442.                                 platformWindow,                    // Macintosh WindowPtr
  2443.                                 frame,                             // Frame type (Persistent/Non-persistent)
  2444.                                 windowProperties->isRootWindow,    // Is this a document window?
  2445.                                 windowProperties->isResizable,    // Is this window resizeable?
  2446.                                 windowProperties->isFloating,    // Is this window floating?
  2447.                                 saveWindow,                        // Should this window be persistent?
  2448.                                 shouldDispose,                    // (see comment above)
  2449.                                 windowProperties->sourceFrame);    // The display frame being opened, if any
  2450.             }
  2451.             
  2452.         CATCH_ALL
  2453.             // Cleanup Macintosh Window.
  2454.             CloseWindow(platformWindow);
  2455.             ODDisposePtr(platformWindow);
  2456.             // Get the right error message for the problem.
  2457.             ODSShort errMsgNum = (!frame && windowProperties->sourceFrame)
  2458.                                     ? kErrCantOpenPartWindow : kErrCantOpenDocWindow;
  2459.             // Alert the user of the problem.
  2460.             this->DoDialogBox(ev, frame, kErrorBoxID, errMsgNum);
  2461.             // Change the exception value, so the DocShell doesn't display an
  2462.             // error dialog.
  2463.             SetErrorCode(kODErrAlreadyNotified);
  2464.             // Alert the caller.
  2465.             RERAISE;
  2466.         ENDTRY
  2467.     }
  2468.  
  2469.     return window;
  2470. }
  2471.  
  2472. //------------------------------------------------------------------------------
  2473. // Method:        CleanupWindow
  2474. // Origin:        PanelEditor
  2475. //
  2476. // Description:    This method is called by the part when a window needs to be
  2477. //                cleaned up for a frame being closed/removed.
  2478. //
  2479. //                The part deallocates the window buffer allocated in the
  2480. //                CreateWindow() method.
  2481. //------------------------------------------------------------------------------
  2482.  
  2483. void PanelEditor::CleanupWindow( Environment*     ev,
  2484.                                 ODFrame*        frame )
  2485. {
  2486.     SOM_Trace("PanelEditor","CleanupWindow");
  2487.     
  2488.        TRY
  2489.         CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2490.         if ( frameInfo->ShouldDisposeWindow() )
  2491.         {
  2492.             TempODWindow window = frame->AcquireWindow(ev);
  2493.             THROW_IF_NULL(window);
  2494.             
  2495.             ODPlatformWindow windowPtr = window->GetPlatformWindow(ev);
  2496.             CloseWindow(windowPtr);
  2497.             ODDisposePtr(windowPtr);
  2498.         }
  2499.     CATCH_ALL
  2500.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrWindowGone);
  2501.         // consume excpetion because it's not fatal.
  2502.     ENDTRY
  2503. }
  2504.  
  2505. //------------------------------------------------------------------------------
  2506. // Method:        GetDefaultWindowProperties
  2507. // Origin:        PanelEditor
  2508. //
  2509. // Description:    This method is called by the part when a new window is being
  2510. //                created. The method examines the frame which is being opened
  2511. //                a generates the default window parameters to pass to the
  2512. //                Mac Toolbox.
  2513. //------------------------------------------------------------------------------
  2514.  
  2515. WindowProperties*
  2516. PanelEditor::GetDefaultWindowProperties( Environment*     ev,
  2517.                                         ODFrame*        sourceFrame,
  2518.                                         Rect*            windowRect )
  2519. {
  2520.     SOM_Trace("PanelEditor","GetDefaultWindowProperties");
  2521.     
  2522.     WindowProperties* windowProperties = new WindowProperties;
  2523.  
  2524.     TRY
  2525.         // Calculate the offset for the window based on the sourceFrame.    
  2526.         if ( sourceFrame )
  2527.             this->CalcPartWindowPosition(ev, sourceFrame, windowRect);
  2528.         else
  2529.             OffsetRect(windowRect, kALittleNudge,
  2530.                         GetMBarHeight() + kMacWindowTitleBarHeight);    
  2531.     
  2532.         // Set the window bounds based on the calculated rect.
  2533.         windowProperties->boundsRect = *windowRect;
  2534.     
  2535.         // Get the part's name to use for the new window.
  2536.         TempODIText windowName = GetPartName(ev, fSelf, kODCategorySpace);
  2537.         // Convert the ODIText into a Pascal string.
  2538.         GetITextString(windowName, windowProperties->title);
  2539.         
  2540.         // Fill in the other fields of the Window Properties struct.
  2541.         
  2542.         windowProperties->procID = zoomDocProc;
  2543.         windowProperties->hasCloseBox = kODTrue;
  2544.         windowProperties->refCon = (long) kODNULL;
  2545.         windowProperties->wasVisible = kODFalse;
  2546.         windowProperties->isResizable = kODTrue;
  2547.         windowProperties->isFloating = kODFalse;
  2548.         windowProperties->isRootWindow = sourceFrame ? kODFalse : kODTrue;
  2549.         windowProperties->shouldShowLinks = kODFalse;
  2550.         windowProperties->sourceFrame = sourceFrame;
  2551.     CATCH_ALL
  2552.         // Clean up and...
  2553.         ODDeleteObject(windowProperties);
  2554.         // Alert the caller.
  2555.         RERAISE;
  2556.     ENDTRY
  2557.     
  2558.     return windowProperties;
  2559. }
  2560.  
  2561. //------------------------------------------------------------------------------
  2562. // Method:        GetSavedWindowProperties
  2563. // Origin:        PanelEditor
  2564. //
  2565. // Description:    This method is called by the part to read in saved information
  2566. //                for a window from an existing document. In addition, the method
  2567. //                 verifies that the window will open visible on some monitor.
  2568. //------------------------------------------------------------------------------
  2569.  
  2570. WindowProperties*
  2571. PanelEditor::GetSavedWindowProperties(    Environment*     ev,
  2572.                                          ODFrame*        frame )
  2573. {
  2574.     SOM_Trace("PanelEditor","GetSavedWindowProperties");
  2575.  
  2576.     WindowProperties* windowProperties = new WindowProperties;
  2577.  
  2578.     // If we fail to load the window properties from storage, delete
  2579.     // the structure so the calling code will behave appropriately.    
  2580.     if ( BeginGetWindowProperties(ev, frame, windowProperties) )
  2581.     {    
  2582.         // Note: We don't call EndGetWindowProperties because it releases the
  2583.         // source frame, which we will need after this method returns.
  2584.         
  2585.         // Get the part's name to use for the new window.
  2586.         TempODIText windowName = GetPartName(ev, fSelf, kODCategorySpace);
  2587.         // Convert the ODIText into a Pascal string.
  2588.         GetITextString(windowName, windowProperties->title);
  2589.     
  2590.         // Verify the window is still visible on a monitor.
  2591.         
  2592.         RgnHandle windowRgn = ODNewRgn();
  2593.         ODBoolean repositionWindow = kODFalse;
  2594.         
  2595.         // We are only concerned with the window's title bar being
  2596.         // visible, so calcuate the titlebar rect from the current
  2597.         // window bounds.
  2598.         Rect adjustedBounds = windowProperties->boundsRect;
  2599.         adjustedBounds.bottom = adjustedBounds.top;
  2600.         adjustedBounds.top -= kMacWindowTitleBarHeight;
  2601.         
  2602.         // Intersect the monitor's region
  2603.         RectRgn(windowRgn, &adjustedBounds);
  2604.         SectRgn(windowRgn, GetGrayRgn(), windowRgn);
  2605.         
  2606.         if ( !EmptyRgn(windowRgn) )
  2607.         {
  2608.             // If the visible portion of the window is too small, we need
  2609.             // to reposition it.
  2610.             Rect intersectedBounds = (**windowRgn).rgnBBox;
  2611.             if ( (intersectedBounds.right-intersectedBounds.left < kMinHorzVisPortion) ||
  2612.                     (intersectedBounds.bottom-intersectedBounds.top < kMinVertVisPortion) )
  2613.                 repositionWindow = kODTrue;
  2614.         }
  2615.         else
  2616.         {
  2617.             // If the window is completely offscreen, we need to reposition it.
  2618.             repositionWindow = kODTrue;
  2619.         }
  2620.         ODDisposeHandle((ODHandle)windowRgn);
  2621.         
  2622.         // If not, we need to move it so the user can see it.
  2623.         if ( repositionWindow )
  2624.         {
  2625.             Rect windowRect = (windowProperties->boundsRect);
  2626.             // Move the window to {0,0} coordinates.
  2627.             OffsetRect(&windowRect, -windowRect.left, -windowRect.top);
  2628.             // Now move the window to the default window position.
  2629.             OffsetRect(&windowRect, kALittleNudge, GetMBarHeight() + kMacWindowTitleBarHeight);
  2630.             // Save the new window position in our windowProperties.
  2631.             windowProperties->boundsRect = windowRect;
  2632.         }
  2633.     }
  2634.     else
  2635.     {
  2636.         // If we were unable to re-load window properties, dispose of the
  2637.         // struct.
  2638.         ODDeleteObject(windowProperties);
  2639.     }
  2640.     
  2641.     return windowProperties;
  2642. }
  2643.  
  2644. //------------------------------------------------------------------------------
  2645. // Method:        CalcPartWindowSize
  2646. // Origin:        PanelEditor
  2647. //
  2648. // Description:    This method is called by the part to determine what size a new
  2649. //                window shoud be.
  2650. //------------------------------------------------------------------------------
  2651.  
  2652. Rect PanelEditor::CalcPartWindowSize( Environment*    ev,
  2653.                                       ODFrame*        sourceFrame )
  2654. {
  2655.     SOM_Trace("PanelEditor","CalcPartWindowSize");
  2656.  
  2657.     Rect windowRect;
  2658.     
  2659.     // If a source frame is given, the part is being asked to open one of
  2660.     // its display frames into a part window. Otherwise, we are being opened
  2661.     // as the root frame of the current document and should size the window
  2662.     // accordingly.
  2663.  
  2664.     // Set up the child window's size to be that of the display frame being opened.
  2665.     if ( sourceFrame )
  2666.     {
  2667.         GetQDFrameBounds(ev, sourceFrame, &windowRect);
  2668.     }
  2669.     // Otherwise, just open a large window.
  2670.     else
  2671.     {
  2672.         SetRect(&windowRect, 0, 0, kDefaultWinWidth, kDefaultWinHeight);
  2673.     }
  2674.     
  2675.     return windowRect;
  2676. }
  2677.  
  2678. //------------------------------------------------------------------------------
  2679. // Method:        CalcPartWindowPosition
  2680. // Origin:        PanelEditor
  2681. //
  2682. // Description:    This method is called by the part to determine where to align
  2683. //                the new window (top left corner of the screen or tiled to a
  2684. //                frame).
  2685. //------------------------------------------------------------------------------
  2686.  
  2687. Rect PanelEditor::CalcPartWindowPosition( Environment*    ev,
  2688.                                           ODFrame*        frame,
  2689.                                           Rect*            partWindowBounds )
  2690. {
  2691.     SOM_Trace("PanelEditor","CalcPartWindowPosition");
  2692.  
  2693.     ODFacet*        activeFacet;
  2694.     ODShape*        frameShape;
  2695.     ODRect            bbox;
  2696.     Rect            bounds;
  2697.     
  2698.     // We need to know which facet of the frame we are opening to position
  2699.     // the child window.
  2700.     activeFacet = this->GetActiveFacetForFrame(ev, frame);
  2701.     
  2702.     // This should never occur, but if it did, it would be fatal.
  2703.     // So we will just pass back the same rectangle.
  2704.     if ( activeFacet == kODNULL )
  2705.         return *partWindowBounds;
  2706.     
  2707.     // For the purposes of tiling, we need the to know the area of the
  2708.     // document the frame occupies. We do this by getting the bouding
  2709.     // box and offsetting it by the aggregate external window transform
  2710.     // of the facet.
  2711.     
  2712.     frameShape = activeFacet->GetFrame(ev)->AcquireFrameShape(ev, kODNULL);
  2713.     TempODTransform windowFrameTransform = activeFacet->AcquireWindowFrameTransform(ev, kODNULL);
  2714.     TempODShape boundsShape = ODCopyAndRelease(ev, frameShape);
  2715.  
  2716.     // Translate the bounds rect into window coordinates.
  2717.     boundsShape->Transform(ev, windowFrameTransform);
  2718.     
  2719.     // Get and convert the bounding box into a QuickDraw rectangle.
  2720.     boundsShape->GetBoundingBox(ev, &bbox);
  2721.     FixedToIntRect(bbox, bounds);
  2722.         
  2723.     // We then call our method to tile the child window.
  2724.     *partWindowBounds = TilePartWindow(ev, &bounds, partWindowBounds);
  2725.     
  2726.     // Set the port and origin so we can convert the rect to
  2727.     // global Window Mgr coordinates.
  2728.     SetPort(activeFacet->GetCanvas(ev)->GetQDPort(ev));
  2729.     SetOrigin(0,-kMacWindowTitleBarHeight);
  2730.     
  2731.     // Convert the local coordinates to global Window Mgr coordinates.
  2732.     LocalToGlobal((Point*)(&(partWindowBounds->top)));
  2733.     LocalToGlobal((Point*)(&(partWindowBounds->bottom)));
  2734.  
  2735.     return *partWindowBounds;
  2736. }
  2737.  
  2738. //------------------------------------------------------------------------------
  2739. // Method:        ZoomPartWindow
  2740. // Origin:        PanelEditor
  2741. //
  2742. // Description:    This method is called by the part when a frame is being opened
  2743. //                or closed in the case that zooming rectangles should be shown.                
  2744. //------------------------------------------------------------------------------
  2745.  
  2746. void PanelEditor::ZoomPartWindow( Environment*        ev,
  2747.                                      ODFrame*            frame,
  2748.                                      ODWindow*            window,
  2749.                                      ODBoolean            openingWindow )
  2750. {
  2751.     SOM_Trace("PanelEditor","ZoomPartWindow");
  2752.  
  2753.     const ODSShort kNumZoomSteps = 12;
  2754.  
  2755.     Rect frameRect;
  2756.     {
  2757.         // We need to know which facet of the frame we are opening to position
  2758.         // the child window.
  2759.         ODFacet* zoomFacet = kODNULL;
  2760.         
  2761.         TRY
  2762.             zoomFacet = this->GetActiveFacetForFrame(ev, frame);
  2763.         CATCH_ALL
  2764.         ENDTRY
  2765.         
  2766.         // In case there isn't an active facet for the frame, .
  2767.         if ( zoomFacet == kODNULL )
  2768.         {
  2769.             TempODFrameFacetIterator iter(ev, frame);
  2770.             zoomFacet = iter.First();
  2771.         }
  2772.         
  2773.         if ( zoomFacet != kODNULL )
  2774.         {
  2775.             // For doing the zoom rects, we need the to know the area of the
  2776.             // document the frame occupies. We do this by getting the bouding
  2777.             // box and offsetting it by the aggregate external window transform
  2778.             // of the facet.
  2779.             TempODTransform windowFrameTransform =
  2780.                                 zoomFacet->AcquireWindowFrameTransform(ev, kODNULL);
  2781.             TempODShape boundsShape =
  2782.                                 ODCopyAndRelease(ev, zoomFacet->GetFrame(ev)
  2783.                                                     ->AcquireFrameShape(ev, kODNULL));
  2784.             
  2785.             // Translate the bounds rect into window coordinates.
  2786.             boundsShape->Transform(ev, windowFrameTransform);
  2787.             
  2788.             // Get and convert the bounding box into a QuickDraw rectangle.
  2789.             ODRect bbox;
  2790.             boundsShape->GetBoundingBox(ev, &bbox);
  2791.             FixedToIntRect(bbox, frameRect);
  2792.                 
  2793.             // Set the port and origin so we can convert the rect to
  2794.             // global Window Mgr coordinates.
  2795.             SetPort(zoomFacet->GetCanvas(ev)->GetQDPort(ev));
  2796.             SetOrigin(0, 0);
  2797.             
  2798.             // Convert the local coordinates to global Window Mgr coordinates.
  2799.             LocalToGlobal((Point*) &frameRect.top);
  2800.             LocalToGlobal((Point*) &frameRect.bottom);
  2801.         }
  2802.     }
  2803.     
  2804.     Rect windowRect;
  2805.     {
  2806.         ODPlatformWindow platformWindow = window->GetPlatformWindow(ev);
  2807.  
  2808.         windowRect = platformWindow->portRect;
  2809.         windowRect.top -= kMacWindowTitleBarHeight;
  2810.         
  2811.         // Set the port and origin so we can convert the rect to
  2812.         // global Window Mgr coordinates.
  2813.         SetPort(platformWindow);
  2814.         SetOrigin(0, 0);
  2815.         
  2816.         // Convert the local coordinates to global Window Mgr coordinates.
  2817.         LocalToGlobal((Point*) &windowRect.top);
  2818.         LocalToGlobal((Point*) &windowRect.bottom);
  2819.     }
  2820.     
  2821.     Rect fromRect = openingWindow ? frameRect  : windowRect;
  2822.     Rect toRect   = openingWindow ? windowRect : frameRect;
  2823.     
  2824.     if ( !openingWindow )
  2825.         window->Hide(ev);
  2826.  
  2827.     ZoomRects(&fromRect, &toRect, kNumZoomSteps, 
  2828.                 openingWindow ? zoomAccelerate : zoomDecelerate);
  2829. }
  2830.  
  2831. //------------------------------------------------------------------------------
  2832. // Method:        GetActiveFacetForFrame
  2833. // Origin:        Panel Editor
  2834. //
  2835. // Description:    This method is called by the part when it needs to know what the
  2836. //                active facet is for the part, if any.
  2837. //
  2838. //                The part uses this method specifically to find the facet of a
  2839. //                source frame when opening a part window.
  2840. //------------------------------------------------------------------------------
  2841.  
  2842. ODFacet* PanelEditor::GetActiveFacetForFrame( Environment*    ev,
  2843.                                               ODFrame*        frame )
  2844. {
  2845.     SOM_Trace("PanelEditor","GetActiveFacetForFrame");
  2846.  
  2847.     ODFacet*    facet = kODNULL;
  2848.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2849.     
  2850.     // If the frame is active, and it should be, get the active facet
  2851.     // from the frame state info.
  2852.     if ( frameInfo->IsFrameActive() )
  2853.     {
  2854.         facet = frameInfo->GetActiveFacet();
  2855.     }
  2856.     else
  2857.     // Otherwise, iterate over the display frames looking for one
  2858.     // that has an active facet... there should be at least one.
  2859.     {
  2860.         TempODFrameFacetIterator fiter(ev, frame);
  2861.         for ( ODFacet* selectedFacet = fiter.First(); fiter.IsNotComplete();
  2862.               selectedFacet = fiter.Next() )
  2863.         {
  2864.             if ( selectedFacet->IsSelected(ev) )
  2865.             {
  2866.                 facet = selectedFacet;
  2867.                 break;
  2868.             }
  2869.         }
  2870.     }
  2871.     
  2872.     // If there are no active facets anywhere, this method should never
  2873.     // have been called, so signal an error.
  2874.     if ( facet == kODNULL )
  2875.         THROW(kODErrInvalidFrame);
  2876.         
  2877.     return facet;
  2878. }
  2879.  
  2880. //==============================================================================
  2881. #pragma mark    • Imaging •
  2882. //==============================================================================
  2883.  
  2884. //------------------------------------------------------------------------------
  2885. // Method:        FacetAdded
  2886. // Origin:        ODPart
  2887. //
  2888. // Description:    This method is called when any part adds a facet to
  2889. //                one of our display frames.
  2890. //
  2891. //                The part calls ViewTypeChanged to load the appropriate
  2892. //                resource for display in this facet and then activates
  2893. //                the frame if we are the root part of an active window.
  2894. //------------------------------------------------------------------------------
  2895.  
  2896. void PanelEditor::FacetAdded(    Environment*    ev,
  2897.                                 ODFacet*        facet )
  2898. {
  2899.     SOM_Trace("PanelEditor","FacetAdded");
  2900.  
  2901.     ODFrame* frame = facet->GetFrame(ev);
  2902.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2903.     
  2904.     // If this is the first facet being added to the frame, we prepare
  2905.     // for drawing in the appropriate view type.
  2906.     
  2907.     // If a frame had all of its facets removed, the frame would have
  2908.     // hidden any of its part windows. If the frame becomes visible again,
  2909.     // by having a facet added to it, we will "show" the part window for
  2910.     // the frame.
  2911.     
  2912.     if ( (CountFramesFacets(ev, frame) == 1) )
  2913.     {
  2914.         TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2915.         if ( window ) window->Show(ev);
  2916.     }
  2917.  
  2918.     // If true, the frameshape we were given is too small. By now, our container
  2919.     // will have a "record" of this frame and we will be able to negotiate for
  2920.     // more space.
  2921.     if ( frameInfo->ShouldNegotiate() )
  2922.     {
  2923.         ODRect bounds;
  2924.         
  2925.         bounds.top = bounds.left = ff(0);
  2926.         bounds.right = ff(this->GetMinWidth());
  2927.         bounds.bottom = ff(this->GetMinHeight());
  2928.         
  2929.         TempODShape frameShape = facet->CreateShape(ev);
  2930.         frameShape->SetRectangle(ev, &bounds);
  2931.         
  2932.         TempODShape returnShape =
  2933.                 facet->GetFrame(ev)->RequestFrameShape(ev, frameShape, kODNULL);
  2934.                 
  2935.         frameInfo->SetShouldNegotiate(kODFalse);
  2936.     }
  2937.  
  2938.     // If this is the root frame/facet of a given window, we should activate
  2939.     // ourselves. This prevents OpenDoc from getting into an ambiguous
  2940.     // state.
  2941.  
  2942.     if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  2943.     {
  2944.         // Ask the list to add a facet to itself.
  2945.         fList->AddFacet(ev, facet);
  2946.     }
  2947.     else if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  2948.     {
  2949.         // add facets to the embedded parts.
  2950.         
  2951.         COrdListIterator fiter(fEmbeddedParts);
  2952.         for ( CListItem* item = (CListItem*)fiter.First();
  2953.                 fiter.IsNotComplete();
  2954.                 item = (CListItem*)fiter.Next() )
  2955.         {
  2956.             item->AddFacet(ev, facet);
  2957.             
  2958.             if ( item == (CListItem*)fEmbeddedParts->First() )
  2959.             {
  2960.                 // Select the first in the list.
  2961.                 fSelection->Add(ev, item);
  2962.                 // Change the panel frame display to the first item.
  2963.                 fPanel->ChangeDisplayItem(ev, item);
  2964.             }
  2965.         }
  2966.  
  2967.         // If a root facet is being added, the frame should be activated when the
  2968.         // window is "selected". This prevents OpenDoc from getting into an
  2969.         // ambiguous state of no part having the selection focus.
  2970.     
  2971.         TempODFrame containingFrame = frame->AcquireContainingFrame(ev);
  2972.         if ( containingFrame->IsRoot(ev) )
  2973.         {
  2974.             frameInfo->SetFrameReactivate(kODTrue);
  2975.             
  2976.             // In addition, we set the "active" facet because the user can
  2977.             // perform edit operations on the part before having clicked
  2978.             // in it. The edit operations (eg. Paste) need to have a facet
  2979.             // for setting up the drawing environment.
  2980.             frameInfo->SetActiveFacet(facet);
  2981.         }
  2982.     }
  2983. }
  2984.  
  2985. //------------------------------------------------------------------------------
  2986. // Method:        FacetRemoved
  2987. // Origin:        ODPart
  2988. //
  2989. // Description:    This method is called when any part removes a facet
  2990. //                from one of our display frames.
  2991. //
  2992. //                The part just removes the "active" note from the
  2993. //                appropriate display frame if necessary since this
  2994. //                facet will not be available, nor active, again.
  2995. //------------------------------------------------------------------------------
  2996.  
  2997. void PanelEditor::FacetRemoved( Environment*    ev,
  2998.                                 ODFacet*        facet )
  2999. {
  3000.     SOM_Trace("PanelEditor","FacetRemoved");
  3001.  
  3002.     ODFrame*    frame = facet->GetFrame(ev);
  3003.     TempODFrame    containingFrame = frame->AcquireContainingFrame(ev);
  3004.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3005.  
  3006.     // If the facet was the active facet, it can no longer be.
  3007.     if ( ODObjectsAreEqual(ev, frameInfo->GetActiveFacet(), facet) )
  3008.         frameInfo->SetActiveFacet(kODNULL);
  3009.  
  3010.     // If a frame has all of its facets removed and its containing frame set
  3011.     // to NULL, the frame becomes "hidden". If the frame owns a part window,
  3012.     // the part window should also be hidden.
  3013.     
  3014.     if ( (CountFramesFacets(ev, frame) == 0) &&
  3015.             (containingFrame == kODNULL) )
  3016.     {
  3017.         TempODWindow window = frameInfo->AcquirePartWindow(ev);
  3018.         if ( window ) window->Hide(ev);
  3019.     }
  3020.     
  3021.     if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  3022.     {
  3023.         // Remove the facets from the frames we've created.
  3024.         fList->RemoveFacet(ev, facet);
  3025.         fPanel->RemoveFacet(ev, facet);
  3026.     }
  3027.     else if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  3028.     {
  3029.         // Iterate over the embedded items to remove facets.
  3030.         COrdListIterator fiter(fEmbeddedParts);
  3031.         for ( CListItem* item = (CListItem*)fiter.First();
  3032.                 fiter.IsNotComplete();
  3033.                 item = (CListItem*)fiter.Next() )
  3034.         {
  3035.             // Ask each item to destroy the appropriate facets.
  3036.             item->RemoveFacet(ev, facet);
  3037.         }
  3038.     }
  3039. }
  3040.  
  3041. //------------------------------------------------------------------------------
  3042. // Method:        AdjustBorderShape
  3043. //
  3044. // Description:    This method is called when
  3045. //------------------------------------------------------------------------------
  3046.  
  3047. ODShape* PanelEditor::AdjustBorderShape(Environment *ev,
  3048.                                         ODFacet* /*embeddedFacet*/,
  3049.                                         ODShape* shape)
  3050. {
  3051.     ODShape* border = kODNULL;
  3052.     
  3053.     // If the shape is non-null, then we are adjusting the active border
  3054.     // for the panel frame.
  3055.     if ( shape )
  3056.     {
  3057.         ODRect bounds;
  3058.         shape->GetBoundingBox(ev, &bounds);
  3059.         
  3060.         bounds.Inset(ff(-1),ff(-1));
  3061.         border = shape->NewShape(ev);
  3062.         border->SetRectangle(ev, &bounds);
  3063.         
  3064.         bounds.Inset(ff(4),ff(4));
  3065.         TempODShape subtShape = shape->NewShape(ev);
  3066.         subtShape->SetRectangle(ev, &bounds);
  3067.         
  3068.         border->Subtract(ev, subtShape);
  3069.     }
  3070.     
  3071.     return border;
  3072. }
  3073.  
  3074. //------------------------------------------------------------------------------
  3075. // Method:        Draw
  3076. //
  3077. // Description:    This method is called when
  3078. //------------------------------------------------------------------------------
  3079. /*
  3080. void PanelEditor::Invalidate(Environment* ev,
  3081.                                 ODFrame* frame)
  3082. {
  3083.     frame->Invalidate(ev, kODNULL, kODNULL);
  3084. }
  3085. */
  3086. //------------------------------------------------------------------------------
  3087. // Method:        Draw
  3088. // Origin:        ODPart
  3089. //
  3090. // Description:    This method is called when a facet of a part's display
  3091. //                frame intersects the invalidated portion of an OpenDoc
  3092. //                window. The invalidShape parameter passed in is the
  3093. //                portion of the facet which has been invalidated.
  3094. //
  3095. //                The part sets up the drawing environment using a
  3096. //                C++ helper class (CFocusFrame) and then calls the
  3097. //                appropriate drawing method based on the frame's
  3098. //                viewType.
  3099. //------------------------------------------------------------------------------
  3100.  
  3101. void PanelEditor::Draw( Environment*    ev,
  3102.                         ODFacet*        facet,
  3103.                         ODShape*        invalidShape )
  3104. {
  3105.     SOM_Trace("PanelEditor","Draw");
  3106.  
  3107.     // Focus the port and origin for drawing in our facet.
  3108.     // Note that this instance of the CFocusDrawingEnv class
  3109.     // is being allocated on the stack. When the execution
  3110.     // leaves the scope of this method, the destructor (which
  3111.     // cleans up the drawing environment) is automatically
  3112.     // called.
  3113.     CFocusFrame initiateDrawing(ev, facet, invalidShape);
  3114. //    CFocusFrame initiateDrawing(ev, facet);
  3115.  
  3116.     ODTypeToken view = facet->GetFrame(ev)->GetViewType(ev);
  3117.     
  3118.     if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView )
  3119.         this->DrawIconView(ev, facet);
  3120.     else if ( view == gGlobals->fThumbnailView )
  3121.         this->DrawThumbnailView(ev, facet);
  3122.     else
  3123.         this->DrawFrameView(ev, facet);
  3124. }
  3125.  
  3126. //------------------------------------------------------------------------------
  3127. // Method:        DrawFrameView
  3128. // Origin:        PanelEditor
  3129. //
  3130. // Description:    This method is called by the part when the frame being
  3131. //                drawn is in "frame" view.
  3132. //------------------------------------------------------------------------------
  3133.  
  3134. void PanelEditor::DrawFrameView( Environment*    ev,
  3135.                                  ODFacet*        facet )
  3136. {
  3137.     SOM_Trace("PanelEditor","DrawFrameView");
  3138.  
  3139.     // check presentation and do the right thing.
  3140.     ODFrame* frame = facet->GetFrame(ev);
  3141.     
  3142.     if ( frame->GetPresentation(ev) == gGlobals->fMainPresentation )
  3143.     {
  3144.         // Fill the background with a light gray color
  3145.         
  3146.         RGBColor backColor;
  3147.         RGBColor rgbLtGray;
  3148.         
  3149.         rgbLtGray.red = rgbLtGray.green = rgbLtGray.blue = kLtGrayColor;
  3150.         
  3151.         // Get the closet color to our "default" from the current color table.
  3152.         Index2Color(Color2Index(&rgbLtGray), &rgbLtGray);
  3153.         
  3154.         GetBackColor(&backColor);
  3155.         RGBBackColor(&rgbLtGray);
  3156.         
  3157.         GrafPtr thePort;
  3158.         GetPort(&thePort);
  3159.         EraseRect(&thePort->portRect);
  3160.         
  3161.         RGBBackColor(&backColor);
  3162.                 
  3163.         PenNormal();
  3164.         Rect box;
  3165.         GetQDFrameBounds(ev, frame, &box);
  3166.         
  3167.         // Leave space for the grow box and status line area.
  3168.         ODUShort slHeight = (frame->IsRoot(ev)) ? 15 : 0;
  3169.         
  3170.         // Draw divider line between list & panel.
  3171.         MoveTo(kDividerLeftEdge, box.top);
  3172.         Line(0, box.bottom-slHeight);
  3173.         
  3174.         // If we are embedded...
  3175.         if ( !frame->IsRoot(ev) )
  3176.         {
  3177.             // Frame the whole part.
  3178.             FrameRect(&box);
  3179.         }
  3180.         else
  3181.         {        
  3182.             // Draw divider line where bottom scroll bar would be.
  3183.             MoveTo(0, box.bottom-15);
  3184.             LineTo(thePort->portRect.right, box.bottom-15);
  3185.         }
  3186.         
  3187.         // Ask the panel to draw itself.
  3188.         fPanel->Draw(ev,facet);
  3189.     }
  3190.     else if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  3191.     {
  3192.         // Ask the list to draw itself.
  3193.         fList->Draw(ev,facet);
  3194.     }
  3195. }
  3196.  
  3197. //------------------------------------------------------------------------------
  3198. // Method:        DrawIconView
  3199. // Origin:        PanelEditor
  3200. //
  3201. // Description:    This method is called by the part when the frame being
  3202. //                drawn is in "standard icon" view.
  3203. //
  3204. //                The part uses the Icon Utilities toolbox manager to
  3205. //                aid in drawing icons in active windows. The Guidelines
  3206. //                require a different appearance for selected icons in
  3207. //                inactive windows, which we do manually.
  3208. //------------------------------------------------------------------------------
  3209.  
  3210. void PanelEditor::DrawIconView( Environment*    ev,
  3211.                                 ODFacet*        facet )
  3212. {
  3213.     SOM_Trace("PanelEditor","DrawIconView");
  3214.  
  3215.     Rect                iconRect;
  3216.     IconTransformType     transformType = ttNone;
  3217.     CFrameInfo*            frameInfo;
  3218.     ODFrame*            frame; 
  3219.     ODTypeToken            viewType;
  3220.     
  3221.     frame        = facet->GetFrame(ev);
  3222.     viewType    = frame->GetViewType(ev);
  3223.     frameInfo     = (CFrameInfo*) frame->GetPartInfo(ev);
  3224.     
  3225.     // Check to see if the facet is selected
  3226.     if ( facet->GetHighlight(ev) == kODFullHighlight )
  3227.         transformType = ttSelected;
  3228.     
  3229.     // Check to see if the frame has been opened into a part window.
  3230.     TempODWindow window = frameInfo->AcquirePartWindow(ev);
  3231.     if ( window && window->IsShown(ev) )
  3232.         transformType |= ttOpen;
  3233.     
  3234.     // Draw the icon.
  3235.     if ( viewType == gGlobals->fLargeIconView )
  3236.         SetRect(&iconRect, 0, 0, kODLargeIconSize, kODLargeIconSize);
  3237.     else // ( viewType == gGlobals->fSmallIconView )
  3238.         SetRect(&iconRect, 0, 0, kODSmallIconSize, kODSmallIconSize);
  3239.  
  3240.     CUsingLibraryResources res;
  3241.     PlotIconID(&iconRect, atAbsoluteCenter, transformType, kBaseResourceID);
  3242. }
  3243.  
  3244. //------------------------------------------------------------------------------
  3245. // Method:        DrawThumbnailView
  3246. // Origin:        PanelEditor
  3247. //
  3248. // Description:    This method is called by the part when the frame being
  3249. //                drawn is in "thumbnail" view.
  3250. //
  3251. //                The part uses a picture for its thumbnail view because
  3252. //                it has no intrinsic content. A picture resource is
  3253. //                probably not sufficient for parts with real content.
  3254. //------------------------------------------------------------------------------
  3255.  
  3256. void PanelEditor::DrawThumbnailView( Environment*    ev,
  3257.                                     ODFacet*        facet )
  3258. {
  3259.     SOM_Trace("PanelEditor","DrawThumbnailView");
  3260.  
  3261.     // Create or retrieve a cached thumbnail picture.
  3262.     PicHandle thumbnail = this->GenerateThumbnail(ev, facet->GetFrame(ev));
  3263.     
  3264.     Rect bounds = (**thumbnail).picFrame;
  3265.     DrawPicture(thumbnail, &bounds);
  3266. }
  3267.  
  3268. //------------------------------------------------------------------------------
  3269. // Method:        GenerateThumbnail
  3270. // Origin:        PanelEditor
  3271. //
  3272. // Description:    This method is called by the part to generate a thumbnail view
  3273. //                from the current content.
  3274. //
  3275. //                The part has no content, so we merely load a picture.
  3276. //------------------------------------------------------------------------------
  3277.  
  3278. PicHandle PanelEditor::GenerateThumbnail( Environment*        ev,
  3279.                                           ODFrame*            frame )
  3280. {
  3281.     SOM_Trace("PanelEditor","GenerateThumbnail");
  3282.     
  3283.     if ( gGlobals->fThumbnail == kODNULL )
  3284.     {
  3285.         // In cases where a part has been instantiated from scratch and has no
  3286.         // content (yet), it is appropriate to display a PICT or some graphic
  3287.         // in place of a "real" thumbnail.
  3288.         
  3289.         LoadThumbnail(ev, &gGlobals->fThumbnail);
  3290.     
  3291.         // If we were unable to load the PICT resource for whatever reason
  3292.         // we will default back to a "frame" view and throw the Resource
  3293.         // Manager error as an exception.
  3294.         if ( gGlobals->fThumbnail == kODNULL )
  3295.         {
  3296.             frame->ChangeViewType(ev, gGlobals->fFrameView);
  3297.             
  3298.             // There is a bug in ResError, when resources are not found,
  3299.             // which may cause noErr to be returned. If that is the case,
  3300.             // we throw resNotFound.
  3301.             THROW_IF_ERROR((ODError)ResError());
  3302.             THROW(resNotFound);
  3303.         }
  3304.     }
  3305.         
  3306.     return (PicHandle)gGlobals->fThumbnail;
  3307. }
  3308.  
  3309. //------------------------------------------------------------------------------
  3310. // Method:        GeometryChanged
  3311. // Origin:        ODPart
  3312. //
  3313. // Description:    This method is called when the ExternalTransform or
  3314. //                ClipShape of a facet on one this part's display frames
  3315. //                changes.
  3316. //------------------------------------------------------------------------------
  3317.  
  3318. void PanelEditor::GeometryChanged( Environment*    ev,
  3319.                                     ODFacet*        facet,
  3320.                                     ODBoolean        clipShapeChanged,
  3321.                                     ODBoolean        /*externalTransformChanged*/ )
  3322. {
  3323.     SOM_Trace("PanelEditor","GeometryChanged");
  3324.  
  3325. }
  3326.  
  3327. //------------------------------------------------------------------------------
  3328. // Method:        HighlightChanged
  3329. // Origin:        ODPart
  3330. //
  3331. // Description:    This method is called when a facet....
  3332. //------------------------------------------------------------------------------
  3333.  
  3334. void PanelEditor::HighlightChanged(Environment* ev, ODFacet* facet)
  3335. {
  3336.     ODFrame* frame = facet->GetFrame(ev);
  3337.     
  3338.     // The frame view has no "special" drawing characteristics
  3339.     // when opened or selected, so we don't need to update our
  3340.     // content.
  3341.     
  3342.     if ( frame->GetViewType(ev) != gGlobals->fFrameView )
  3343.         frame->Invalidate(ev, kODNULL, kODNULL);
  3344. }
  3345.  
  3346. //==============================================================================
  3347. #pragma mark    • Activation •
  3348. //==============================================================================
  3349.  
  3350. //------------------------------------------------------------------------------
  3351. // Method:        BeginRelinquishFocus
  3352. // Origin:        ODPart
  3353. //
  3354. // Description:    This method is called when another part (or possibly
  3355. //                ourself) is requesting a focus for one of its display
  3356. //                frames. Returning true means we are willing to give
  3357. //                up the requested focus.
  3358. //
  3359. //                The part willingly gives up any focus unless it is the
  3360. //                modal focus which we don't want to give up until we
  3361. //                are completely done displaying a modal dialog.
  3362. //------------------------------------------------------------------------------
  3363.  
  3364. ODBoolean PanelEditor::BeginRelinquishFocus( Environment*    ev,
  3365.                                             ODTypeToken        focus,
  3366.                                             ODFrame*        /*ownerFrame*/,
  3367.                                             ODFrame*        proposedFrame )
  3368. {
  3369.     SOM_Trace("PanelEditor","BeginRelinquishFocus");
  3370.  
  3371.     ODBoolean willRelinquish = kODTrue;
  3372.  
  3373.     // Another part is trying to put up a Modal dialog while we
  3374.     // are currently displaying ours. Deny the request.
  3375.     if ( focus == gGlobals->fModalFocus )
  3376.     {
  3377.         TempODPart proposedPart = proposedFrame->AcquirePart(ev);
  3378.         if ( ODObjectsAreEqual(ev, proposedPart, fSelf) == kODFalse)
  3379.             willRelinquish = kODFalse;
  3380.     }
  3381.                 
  3382.     return willRelinquish;
  3383. }
  3384.  
  3385. //------------------------------------------------------------------------------
  3386. // Method:        CommitRelinquishFocus
  3387. // Origin:        ODPart
  3388. //
  3389. // Description:    This method is called when it is actually time to give
  3390. //                up a focus that had been requested by another part (or
  3391. //                possibly ourself).
  3392. //
  3393. //                The part calls its FocusLost method to handle the 
  3394. //                "reliquishing" of the particular focus.
  3395. //------------------------------------------------------------------------------
  3396.  
  3397. void PanelEditor::CommitRelinquishFocus( Environment*    ev,
  3398.                                         ODTypeToken        focus,
  3399.                                         ODFrame*        ownerFrame,
  3400.                                         ODFrame*        /*proposedFrame*/ )
  3401. {
  3402.     SOM_Trace("PanelEditor","CommitRelinquishFocus");
  3403.  
  3404.     // We agreed to give up our FocusSet and now we are being asked to
  3405.     // do so.
  3406.     this->FocusLost(ev, focus, ownerFrame);
  3407. }
  3408.  
  3409. //------------------------------------------------------------------------------
  3410. // Method:        AbortRelinquishFocus
  3411. // Origin:        ODPart
  3412. //
  3413. // Description:    This method is called when another part (or possibly
  3414. //                ourself) requested a focus for one of its display
  3415. //                frames, but we returned kODFalse from
  3416. //                BeginRelinqishFocus for one, or all, of the requested
  3417. //                focus. At this point, we are being told to resume
  3418. //                ownership of the focus.
  3419. //
  3420. //                The part calls its FocusAcquired method to handle the 
  3421. //                re-"acquisition" of the particular focus.
  3422. //------------------------------------------------------------------------------
  3423.  
  3424. void PanelEditor::AbortRelinquishFocus( Environment*        ev,
  3425.                                        ODTypeToken        /*focus*/,
  3426.                                        ODFrame*            /*ownerFrame*/,
  3427.                                        ODFrame*            /*proposedFrame*/ )
  3428. {
  3429.     SOM_Trace("PanelEditor","AbortRelinquishFocus");
  3430.  
  3431.     // Some parts may have suspended some events in the BeginRelinquishFocus
  3432.     // method. If so, they would resume those events here.
  3433. }
  3434.  
  3435. //------------------------------------------------------------------------------
  3436. // Method:        FocusAcquired
  3437. // Origin:        ODPart
  3438. //
  3439. // Description:    This method is called when the Arbitrator has
  3440. //                registered us as the "owner" of the particular focus.
  3441. //                This can occur if we are explicitly assigned a focus, or if a
  3442. //                focus is transfered to one of the part's display frames.
  3443. //
  3444. //                The part will request the other foci it needs to be "active". If
  3445. //                the part is successful, we notify ourself to become active.
  3446. //------------------------------------------------------------------------------
  3447.  
  3448. void PanelEditor::FocusAcquired( Environment*    ev,
  3449.                                 ODTypeToken        focus,
  3450.                                 ODFrame*        ownerFrame )
  3451. {
  3452.     SOM_Trace("PanelEditor","FocusAcquired");
  3453.  
  3454.     ODArbitrator* arbitrator =  fSelf->GetStorageUnit(ev)->GetSession(ev)
  3455.                                     ->GetArbitrator(ev);
  3456.  
  3457.     if ( focus == gGlobals->fMenuFocus )
  3458.     {
  3459.         if ( arbitrator->RequestFocus(ev, gGlobals->fSelectionFocus, ownerFrame) )
  3460.         {
  3461.             this->PartActivated(ev, ownerFrame);
  3462.         }
  3463.     }
  3464.     else if ( focus == gGlobals->fSelectionFocus )
  3465.     {
  3466.         if ( arbitrator->RequestFocus(ev, gGlobals->fMenuFocus, ownerFrame) )
  3467.         {
  3468.             this->PartActivated(ev, ownerFrame);
  3469.         }
  3470.     }
  3471. }
  3472.  
  3473. //------------------------------------------------------------------------------
  3474. // Method:        FocusLost
  3475. // Origin:        ODPart
  3476. //
  3477. // Description:    This method is called when the Arbitrator has
  3478. //                unregistered us as the "owner" of the particular
  3479. //                focus.
  3480. //
  3481. //                The part unmarks the active frame if the selection
  3482. //                focus is lost.
  3483. //------------------------------------------------------------------------------
  3484.  
  3485. void PanelEditor::FocusLost( Environment*    ev,
  3486.                             ODTypeToken        focus,
  3487.                             ODFrame*        ownerFrame )
  3488. {
  3489.     SOM_Trace("PanelEditor","FocusLost");
  3490.  
  3491.     if ( focus == gGlobals->fSelectionFocus )
  3492.     {
  3493.         CFrameInfo* frameInfo = (CFrameInfo*) ownerFrame->GetPartInfo(ev);
  3494.         frameInfo->SetFrameActive(kODFalse);
  3495.     }
  3496. }
  3497.  
  3498. //------------------------------------------------------------------------------
  3499. // Method:        RelinquishAllFoci
  3500. // Origin:        PanelEditor
  3501. //
  3502. // Description:    This method is called when a frame is going away. The method
  3503. //                relinquishes all foci the frame owns.
  3504. //------------------------------------------------------------------------------
  3505.  
  3506. void PanelEditor::RelinquishAllFoci( Environment*    ev,
  3507.                                     ODFrame*        frame )
  3508. {
  3509.     SOM_Trace("PanelEditor","RelinquishAllFoci");
  3510.  
  3511.     ODArbitrator* arbitrator = ODGetSession(ev, fSelf)->GetArbitrator(ev);
  3512.     
  3513.     TRY
  3514.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fSelectionFocus);
  3515.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  3516.         {
  3517.             arbitrator->RelinquishFocus(ev, gGlobals->fSelectionFocus, frame);
  3518.             this->FocusLost(ev, gGlobals->fSelectionFocus, frame);
  3519.         }
  3520.     CATCH_ALL
  3521.     ENDTRY
  3522.  
  3523.     TRY
  3524.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fMenuFocus);
  3525.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  3526.         {
  3527.             arbitrator->RelinquishFocus(ev, gGlobals->fMenuFocus, frame);
  3528.             this->FocusLost(ev, gGlobals->fMenuFocus, frame);
  3529.         }
  3530.     CATCH_ALL
  3531.     ENDTRY
  3532.  
  3533.     TRY
  3534.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fKeyboardFocus);
  3535.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  3536.         {
  3537.             arbitrator->RelinquishFocus(ev, gGlobals->fKeyboardFocus, frame);
  3538.             this->FocusLost(ev, gGlobals->fKeyboardFocus, frame);
  3539.         }
  3540.     CATCH_ALL
  3541.     ENDTRY
  3542. }
  3543.  
  3544. //------------------------------------------------------------------------------
  3545. // Method:        PartActivated
  3546. // Origin:        PanelEditor
  3547. //
  3548. // Description:    This method is called
  3549. //------------------------------------------------------------------------------
  3550.  
  3551. void PanelEditor::PartActivated( Environment* ev, ODFrame* frame )
  3552. {
  3553.     SOM_Trace("PanelEditor","PartActivated");
  3554.     
  3555.     // We are required to re-validate the menubar before displaying it because
  3556.     // any part can/could swap the base menubar at any time.
  3557.     if ( gGlobals->fMenuBar->IsValid(ev) == kODFalse )
  3558.     {
  3559.         ODReleaseObject(ev, gGlobals->fMenuBar);
  3560.         gGlobals->fMenuBar = ODGetSession(ev,fSelf)->GetWindowState(ev)->CopyBaseMenuBar(ev);
  3561.         
  3562.         // After copying the "new" base menu bar, don't forget to re-install
  3563.         // your part's menus.
  3564.     }
  3565.         
  3566.     // Display our menu bar.
  3567.     gGlobals->fMenuBar->Display(ev);
  3568.     
  3569.     // And set our "active" state.
  3570.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3571.     frameInfo->SetFrameActive(kODTrue);
  3572. }
  3573.  
  3574. //------------------------------------------------------------------------------
  3575. // Method:        ActivatePart
  3576. // Origin:        PanelEditor
  3577. //
  3578. // Description:    This method is called by the part when a kODEvtMouseUp
  3579. //                occurs in an inactive frame in an active window, and
  3580. //                when an OpenDoc document comes forward.
  3581. //
  3582. //                The part activates the frame by requesting the
  3583. //                UIFocusSet (created in Initialize) and by calling
  3584. //                FocusAcquired if we were successful. The method
  3585. //                returns true if no problems were encountered as a
  3586. //                signal to the caller that the part is now "active".
  3587. //------------------------------------------------------------------------------
  3588.  
  3589. ODBoolean PanelEditor::ActivateFrame( Environment* ev, ODFrame* frame )
  3590. {
  3591.     SOM_Trace("PanelEditor","ActivatePart");
  3592.  
  3593.     ODBoolean activated = kODFalse;
  3594.  
  3595.     // Request the set of foci necessary to become active.
  3596.     if ( ODGetSession(ev,fSelf)->GetArbitrator(ev)
  3597.             ->RequestFocusSet(ev, gGlobals->fUIFocusSet, frame) )
  3598.     {
  3599.         // Activate the part.
  3600.         this->PartActivated(ev, frame);
  3601.         // We were able to become active.
  3602.         activated = kODTrue;
  3603.     }
  3604.     
  3605.     // Let our caller know we succeded or failed.
  3606.     return activated;
  3607. }
  3608.  
  3609. //------------------------------------------------------------------------------
  3610. // Method:        WindowActivating
  3611. // Origin:        PanelEditor
  3612. //
  3613. // Description:    This method is called by the part when a window we are displayed
  3614. //                in changes from active to inactive, or the reverse.
  3615. //
  3616. //                The part records the active frame, if any of the
  3617. //                display frames were active, so that the frame can be
  3618. //                re-activated when the document is switched into the
  3619. //                foreground.
  3620. //------------------------------------------------------------------------------
  3621.  
  3622. void PanelEditor::WindowActivating( Environment*    ev,
  3623.                                     ODFrame*        frame,
  3624.                                     ODBoolean        activating )
  3625. {
  3626.     SOM_Trace("PanelEditor","WindowActivating");
  3627.  
  3628.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3629.     
  3630.     // The window is being activated and we had the selection focus when
  3631.     // the window was deactivated, so request it again.
  3632.     if ( activating && frameInfo->FrameNeedsReactivating() )
  3633.     {
  3634.         this->ActivateFrame(ev, fList->GetFrame(ev, frame));
  3635.         frameInfo->SetFrameReactivate(kODFalse);
  3636.     }
  3637.     // The window is being deactivated and we have the active part.
  3638.     // So give up our foci and remind ourselves that we need to request
  3639.     // the focus when the window is reactivated.
  3640.     else if ( !activating && frameInfo->IsFrameActive() )
  3641.     {
  3642.         frameInfo->SetFrameReactivate(kODTrue);
  3643.     }
  3644.     
  3645.     // The selection highlighting needs to change.
  3646.     fSelection->Activate(ev, frame, activating);
  3647. }
  3648.  
  3649. //------------------------------------------------------------------------------
  3650. // Method:        ProcessActivating
  3651. // Origin:        PanelEditor
  3652. //
  3653. // Description:    This method is called by the part when a process
  3654. //                switch event (kODEvtOS) occurs.
  3655. //
  3656. //                The part updates the highlighting of the selected items.
  3657. //------------------------------------------------------------------------------
  3658.  
  3659. void PanelEditor::ProcessActivating(Environment* ev,
  3660.                                     ODFrame*    frame, 
  3661.                                     ODBoolean    resume    )
  3662. {
  3663.     SOM_Trace("PanelEditor","ProcessActivating");
  3664.  
  3665.     // The selection highlighting needs to change.
  3666.     fSelection->Activate(ev, frame, resume);
  3667. }
  3668.  
  3669. //==============================================================================
  3670. #pragma mark    • Event Handling •
  3671. //==============================================================================
  3672.  
  3673. //------------------------------------------------------------------------------
  3674. // Method:        HandleEvent
  3675. // Origin:        ODPart
  3676. //
  3677. // Description:    The method is called when an event, which falls into
  3678. //                the category of an owned focus, occurs. The two
  3679. //                exceptions to this are "mouse movement" events and 
  3680. //                embedded frame events, which can occur when a part
  3681. //                owns no foci.
  3682. //
  3683. //                The part returns true if the event was handled.
  3684. //------------------------------------------------------------------------------
  3685.  
  3686.  
  3687. ODBoolean PanelEditor::HandleEvent( Environment*        ev,
  3688.                                    ODEventData*        event,
  3689.                                    ODFrame*            frame,
  3690.                                    ODFacet*            facet,
  3691.                                    ODEventInfo*        eventInfo )
  3692. {
  3693.     SOM_Trace("PanelEditor","HandleEvent");
  3694.  
  3695.     ODBoolean    eventHandled = kODFalse;
  3696.  
  3697.     // Event handling is basically the same as standard Macintosh applications,
  3698.     // except that the events have been renamed for cross-platform compatability.
  3699.     
  3700.     switch ( event->what )
  3701.     {
  3702.         case kODEvtMouseDownEmbedded:
  3703.         case kODEvtMouseUpEmbedded:
  3704.         case kODEvtMouseDown:
  3705.         case kODEvtMouseUp:
  3706.             eventHandled = this->HandleMouseEvent(ev, event, facet, eventInfo);
  3707.             break;
  3708.                         
  3709.         case kODEvtKeyDown:
  3710.         case kODEvtAutoKey:
  3711.             // handle type selection in list
  3712.             break;
  3713.  
  3714.         case kODEvtMenu:
  3715.             eventHandled = this->HandleMenuEvent(ev, event, frame);
  3716.             break;
  3717.  
  3718.         case kODEvtActivate:
  3719.             // We are being notified that a window we are displayed in has
  3720.             // just been de/activated (un/hilighted).
  3721.             this->WindowActivating(ev, frame, (event->modifiers & activeFlag));
  3722.             eventHandled = kODTrue;
  3723.             break;
  3724.     
  3725.         case kODEvtOS:
  3726.             this->ProcessActivating(ev, frame, (event->message & resumeFlag));
  3727.                 // We are being notified that a window we are display in has
  3728.                 // just been suspened/resumed.
  3729.             eventHandled = kODTrue;
  3730.             break;
  3731.         
  3732.         case kODEvtMouseEnter:
  3733.         case kODEvtMouseLeave:
  3734.             SetCursor(&ODQDGlobals.arrow);
  3735.             eventHandled = kODTrue;
  3736.             break;
  3737.  
  3738.         case kODEvtMouseWithin:
  3739.             eventHandled = kODTrue;
  3740.             break;
  3741.  
  3742.         // $$$$$ remove when done
  3743.         case kODEvtNull:
  3744.         case kODEvtMouseDownBorder:
  3745.         case kODEvtMouseUpBorder:
  3746.         case kODEvtWindow:
  3747.         case kODEvtKeyUp:
  3748.         case kODEvtDisk:
  3749.         
  3750.         default:
  3751.             break;
  3752.     }
  3753.  
  3754.     return eventHandled;
  3755. }
  3756.  
  3757. //------------------------------------------------------------------------------
  3758. // Method:        AdjustMenus
  3759. //
  3760. // Description:    This method is called when a kODEvtMouseDown event
  3761. //                occurs in the menubar and the part owns the "menu"
  3762. //                focus.
  3763. //
  3764. //                The part enables the appropriate items for its current
  3765. //                state and updates the menu items to reflect this
  3766. //                editor.
  3767. //------------------------------------------------------------------------------
  3768.  
  3769. void PanelEditor::AdjustMenus(    Environment*    ev,
  3770.                                  ODFrame*        frame )
  3771. {
  3772.     SOM_Trace("PanelEditor","AdjustMenus");
  3773.  
  3774.     // The menubar object always calls the root part's AdjustMenus method before
  3775.     // calling the menu focus owner's. Because of this, we need to validate the
  3776.     // menubar in the case where we are the root part.
  3777.     if ( frame->IsRoot(ev) )
  3778.     {
  3779.         // We are required to re-validate the menubar before displaying it because
  3780.         // any part can/could swap the base menubar at any time.
  3781.         if ( gGlobals->fMenuBar->IsValid(ev) == kODFalse )
  3782.         {
  3783.             ODReleaseObject(ev, gGlobals->fMenuBar);
  3784.             gGlobals->fMenuBar = ODGetSession(ev,fSelf)->GetWindowState(ev)->CopyBaseMenuBar(ev);
  3785.             
  3786.             // After copying the "new" base menu bar, don't forget to re-install
  3787.             // your part's menus.
  3788.         }
  3789.  
  3790.         // We support printing.
  3791.         gGlobals->fMenuBar->EnableCommand(ev, kODCommandPageSetup, kODTrue);
  3792.         gGlobals->fMenuBar->EnableCommand(ev, kODCommandPrint, kODTrue);
  3793.     }
  3794.     
  3795.     // We only need to adjust the menu when the list frame owns the menu focus.
  3796.     if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  3797.     {
  3798.         // Enable the "View As Window" command when we are not the root part.
  3799.         TempODFrame containingFrame = frame->AcquireContainingFrame(ev);
  3800.         gGlobals->fMenuBar->EnableCommand(ev, kODCommandViewAsWin, !containingFrame->IsRoot(ev));
  3801.  
  3802.         TRY
  3803.             Str63 text;
  3804.             
  3805.             // Get the "about" string from our library's resources.
  3806.             // (note: ODGetIndString focuses the resource fork for us)
  3807.             ODGetIndString(text, kMenuStringResID, kAboutTextID);
  3808.             // Create an IText object to pass into the menubar.
  3809.             TempODIText    menuItem(CreateIText(gGlobals->fEditorsScript, gGlobals->fEditorsLanguage,
  3810.                                     (StringPtr)&text));
  3811.             // Change the "About" menu item text for our part.
  3812.             gGlobals->fMenuBar->SetItemString(ev, kODCommandAbout, menuItem);
  3813.         CATCH_ALL
  3814.             // consume exception
  3815.         ENDTRY
  3816.                 
  3817. #ifndef PE_ViewerBuild
  3818.         TRY
  3819.             ODBoolean haveSelection = !fSelection->IsEmpty();
  3820.             
  3821.             // Enable these commands if there is a selection.
  3822.             gGlobals->fMenuBar->EnableCommand(ev, kODCommandCut, haveSelection);
  3823.             gGlobals->fMenuBar->EnableCommand(ev, kODCommandCopy, haveSelection);
  3824.             gGlobals->fMenuBar->EnableCommand(ev, kODCommandClear, haveSelection);
  3825.             gGlobals->fMenuBar->EnableCommand(ev, kODCommandGetPartInfo, haveSelection);
  3826.             
  3827.             ODBoolean haveData = this->CheckClipboard(ev, frame);
  3828.     
  3829.             // Enable these commands if there is data on the clipboard.
  3830.             gGlobals->fMenuBar->EnableCommand(ev, kODCommandPaste, haveData);
  3831.         CATCH_ALL
  3832.             // consume exception
  3833.         ENDTRY
  3834. #endif
  3835.     }    
  3836. }
  3837.  
  3838. //------------------------------------------------------------------------------
  3839. // Method:        HandleMenuEvent
  3840. // Origin:        PanelEditor
  3841. //
  3842. // Description:    This method is called by the part when a menu event is
  3843. //                received.
  3844. //
  3845. //                Using the menu bar object, we determine what the menu
  3846. //                command is, and call the appropriate method to handle
  3847. //                it.
  3848. //------------------------------------------------------------------------------
  3849.  
  3850. ODBoolean PanelEditor::HandleMenuEvent( Environment*    ev,
  3851.                                         ODEventData*        event,
  3852.                                         ODFrame*            frame )
  3853. {
  3854.     SOM_Trace("PanelEditor","HandleMenuEvent");
  3855.  
  3856.     ODULong        menuResult    = event->message;
  3857.     ODUShort    menu        = HiWord(menuResult);
  3858.     ODUShort    item        = LoWord(menuResult);
  3859.  
  3860.     switch ( gGlobals->fMenuBar->GetCommand(ev, menu, item) )
  3861.     {
  3862.         case kODCommandAbout:    
  3863.             this->DoDialogBox(ev, frame, kAboutBoxID);
  3864.             break;
  3865.  
  3866.         case kODCommandPageSetup:
  3867.             // If the user modified page setup, the print
  3868.             // job needs to be saved. We don't call our
  3869.             // internal SetDirty() method because the change
  3870.             // doesn't affect content.
  3871.             if ( fPrinter && fPrinter->PageSetup(ev) )
  3872.                 ODGetDraft(ev, fSelf)->SetChangedFromPrev(ev);
  3873.             break;
  3874.             
  3875.         case kODCommandPrint:
  3876.             if ( fPrinter )
  3877.             {
  3878.                 TempODFrame containingFrame(kODNULL);
  3879.                 
  3880.                 if ( frame->IsRoot(ev) )
  3881.                 {
  3882.                     ODAcquireObject(ev, frame);
  3883.                     containingFrame = frame;
  3884.                 }
  3885.                 else
  3886.                 {
  3887.                     containingFrame = frame->AcquireContainingFrame(ev);
  3888.                 }
  3889.                 
  3890.                 ODFrame* panelFrame = fPanel->GetContainedFrame(ev, containingFrame);
  3891.                 if ( panelFrame )
  3892.                     fPrinter->PrintDocument(ev, panelFrame);
  3893.             }
  3894.             break;
  3895.  
  3896.         case kODCommandViewAsWin:
  3897.             this->Open(ev, frame);
  3898.             break;
  3899.  
  3900.         case kODCommandCut:
  3901.             this->DoCut(ev, frame);
  3902.             break;
  3903.  
  3904.         case kODCommandCopy:
  3905.             this->DoCopy(ev, frame);
  3906.             break;
  3907.  
  3908.         case kODCommandPaste:
  3909.             this->DoPaste(ev, frame);
  3910.             break;
  3911.  
  3912.         case kODCommandPasteAs:
  3913.             this->DoPasteAs(ev, frame);
  3914.             break;
  3915.  
  3916.         case kODCommandClear:
  3917.             this->DoClear(ev, frame);
  3918.             break;
  3919.  
  3920.         case kODCommandGetPartInfo:
  3921.             this->DoPartInfo(ev, frame);
  3922.             break;
  3923.  
  3924.  
  3925.         // Other commands a part might handle
  3926.         case kODCommandOpen:
  3927.         case kODCommandInsert:
  3928.         case kODCommandSelectAll:
  3929.         case kODCommandPreferences:
  3930.         case kODCommandUndo:
  3931.         case kODCommandRedo:
  3932.  
  3933.         default:
  3934.             return kODFalse;
  3935.     }
  3936.         
  3937.     return kODTrue;
  3938. }
  3939.  
  3940. //------------------------------------------------------------------------------
  3941. // Method:        HandleMouseEvent
  3942. //
  3943. // Description:    This method is called by the part when a mouse event
  3944. //                is recieved.
  3945. //
  3946. //                A typical part would determine the event type(up/down)
  3947. //                and respond appropriately, but we have no "real"
  3948. //                content model, so we activate the part as appropriate
  3949. //                and call a generic method to handle the event.
  3950. //
  3951. // Remember:    When a frame is inactive, the first mouse up event
  3952. //                should activate it; inactive frames do not recieve
  3953. //                kODEvtMouseDown events.
  3954. //------------------------------------------------------------------------------
  3955.  
  3956. ODBoolean PanelEditor::HandleMouseEvent( Environment*    ev,
  3957.                                         ODEventData*    event,
  3958.                                         ODFacet*        facet,
  3959.                                         ODEventInfo*    eventInfo )
  3960. {
  3961.     SOM_Trace("PanelEditor","HandleMouseEvent");
  3962.  
  3963.     ODFrame* frame = facet->GetFrame(ev);
  3964.                     
  3965.     // If the facet parameter is invalid, the mouse up occurred outside the
  3966.     // bounds of a Modal window, otherwise it should be treated normally.
  3967.     
  3968.     if ( facet != kODNULL )
  3969.     {
  3970.         ODWindow* window = facet->GetWindow(ev);
  3971.  
  3972.         Point where;
  3973.  
  3974.         // Get the localized mouse coordinates from the Event Info.
  3975.         where.h = FixedToInt(eventInfo->where.x);
  3976.         where.v = FixedToInt(eventInfo->where.y);
  3977.     
  3978.         if ( event->what == kODEvtMouseUp || event->what == kODEvtMouseUpEmbedded )
  3979.         {
  3980.             TRY
  3981.                 // Activate inactive windows on the first mouse up event.
  3982.                 if ( !window->IsActive(ev) )
  3983.                     window->Select(ev);
  3984.                 // Activate the frame (if needed) on all subsequent mouse up events.
  3985.                 else
  3986.                 {
  3987.                     // Get our state information from the PartInfo of the frame.
  3988.                     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3989.  
  3990.                     // If this frame is not the active one, activate it by requesting
  3991.                     // the appropriate foci.
  3992.         
  3993.                     if ( !frameInfo->IsFrameActive() )
  3994.                     {
  3995.                         if ( this->ActivateFrame(ev, fList->GetFrame(ev, frame)) )
  3996.                             // Keep track of which facet was the last active for positioning
  3997.                             // child windows.
  3998.                             frameInfo->SetActiveFacet(facet);
  3999.                         else
  4000.                             // We were unable to acquire the necessary focus and activate it.
  4001.                             return kODFalse;
  4002.                     }
  4003.                 }
  4004.             CATCH_ALL
  4005.                 // exception consumed
  4006.             ENDTRY
  4007.         }
  4008.         else if ( event->what == kODEvtMouseDown )
  4009.         {
  4010.             // The root frame should never handle mouse events.
  4011.             if ( frame->GetPresentation(ev) == gGlobals->fListPresentation )
  4012.             {            
  4013.                 CScrollbar* scrollbar = (CScrollbar*) facet->GetPartInfo(ev);
  4014.                 
  4015.                 //  Hit test scrollbar. If the click is in the scrollbar,
  4016.                 // scroll the list; otherwise check for a hit on an item name.
  4017.                 if ( scrollbar->HitTest(where) > 0 )
  4018.                 {
  4019.                     scrollbar->Scroll(ev, frame, where);
  4020.                 }
  4021.                 else
  4022.                 {
  4023.                     CListItem* item = kODNULL;
  4024.                     
  4025.                     // Select the item so the user gets instant feedback.
  4026.                     if ( fList->HitTest(ev, facet, kODNULL, where, &item) )
  4027.                     {
  4028.                         // Remove all items from the selection.
  4029.                         fSelection->Empty(ev, kODTrue);
  4030.                         // Add the item to the selection if it's not already.
  4031.                         fSelection->Add(ev, item);
  4032.                         // Change the panel frame display to the newly selected item.
  4033.                         fPanel->ChangeDisplayItem(ev, item);
  4034.                     }
  4035.                 }
  4036.             }
  4037.         }
  4038.         else if ( event->what == kODEvtMouseDownEmbedded )
  4039.         {
  4040.             CListItem* item = kODNULL;
  4041.             
  4042.             // Select the item so the user gets instant feedback.
  4043.             if ( fList->HitTest(ev, facet, eventInfo->embeddedFacet, where, &item) )
  4044.             {
  4045.                 // Remove all items from the selection.
  4046.                 fSelection->Empty(ev, kODTrue);
  4047.                 // Add the item to the selection if it's not already.
  4048.                 fSelection->Add(ev, item);
  4049.             }
  4050.             
  4051.             // Check to see if the user is attempting to drag the item.
  4052.             if ( fSelection->CheckForDrag(ev, event) )
  4053.             {
  4054.                 // Drag the selected item.
  4055.                 fSelection->Drag(ev, facet, event, eventInfo);
  4056.                     
  4057.                 // Verify list item positions and adjust the scrollbar setting.
  4058.                 fList->AdjustItemPositions(ev);
  4059.                 fList->AdjustScrollbar(ev);
  4060.                 
  4061.                 // Force redrawing.
  4062.                 frame->Invalidate(ev, kODNULL, kODNULL);
  4063.             }
  4064.             else // If the event is just a click, update the panel display.
  4065.             {
  4066.                 if ( item )
  4067.                     // Change the panel frame display to the newly selected item.
  4068.                     fPanel->ChangeDisplayItem(ev, item);
  4069.             }
  4070.         }
  4071.     }
  4072.     else
  4073.     {
  4074.         // User clicked outside the bounds of a Modal window, though we actually
  4075.         // never display one.
  4076.         
  4077.         SysBeep(1);
  4078.     }
  4079.  
  4080.     return kODTrue;
  4081. }
  4082.  
  4083. //------------------------------------------------------------------------------
  4084. // Method:        CheckClipboard
  4085. // Origin:        PanelEditor
  4086. //
  4087. // Description:    This method is called by the part to check the clipboard for
  4088. //                valid data (stuff that can be pasted).
  4089. //------------------------------------------------------------------------------
  4090.  
  4091. ODBoolean PanelEditor::CheckClipboard(Environment* ev, ODFrame* frame)
  4092. {
  4093.     SOM_Trace("PanelEditor","CheckClipboard");
  4094.  
  4095.     ODBoolean hasValidData = kODFalse;
  4096.  
  4097.     ODSession* session = ODGetSession(ev,fSelf);
  4098.     ODArbitrator* arbitrator = session->GetArbitrator(ev);
  4099.     ODClipboard* clipboard = session->GetClipboard(ev);
  4100.  
  4101.     if ( arbitrator->RequestFocus(ev, gGlobals->fClipboardFocus, frame) )
  4102.     {
  4103.         ODStorageUnit* su = clipboard->GetContentStorageUnit(ev);    
  4104.         
  4105.         if ( su->Exists(ev, kODPropContents, kODNULL, 0) )
  4106.             hasValidData = kODTrue;
  4107.     
  4108.         arbitrator->RelinquishFocus(ev, gGlobals->fClipboardFocus, frame);
  4109.     }
  4110.     
  4111.     return hasValidData;
  4112. }
  4113.  
  4114. //------------------------------------------------------------------------------
  4115. // Method:        GetItemNearSelection
  4116. // Origin:        PanelEditor
  4117. //
  4118. // Description:    This method is called to update the selected item. This will
  4119. //                typically be called after the user "removes" a list item.
  4120. //------------------------------------------------------------------------------
  4121.  
  4122. CListItem* PanelEditor::GetItemNearSelection()
  4123. {
  4124.     // Grab the selection bounds so we can updated it after cutting
  4125.     // the selected items.
  4126.     CListItem* first = fSelection->GetFirstItem();
  4127.     CListItem* last = fSelection->GetLastItem();
  4128.  
  4129.     CListItem* item = kODNULL;
  4130.  
  4131.     if ( fEmbeddedParts->Count() > 1 )
  4132.     {
  4133.         item = (CListItem*) fEmbeddedParts->Before(first);
  4134.         if ( item == kODNULL )
  4135.             item = (CListItem*) fEmbeddedParts->After(last);
  4136.     }
  4137.         
  4138.     return item;
  4139. }
  4140.  
  4141. //------------------------------------------------------------------------------
  4142. // Method:        UpdateSelection
  4143. // Origin:        PanelEditor
  4144. //
  4145. // Description:    This method is called to update the selected item. This will
  4146. //                typically be called after the user "removes" a list item.
  4147. //------------------------------------------------------------------------------
  4148.  
  4149. void PanelEditor::UpdateSelection(Environment* ev, CListItem* item)
  4150. {
  4151.     if ( item )
  4152.     {
  4153.         // Select the item.
  4154.         fSelection->Add(ev, item);
  4155.         // Update the panel display.
  4156.         fPanel->ChangeDisplayItem(ev, item);
  4157.     }
  4158.     else
  4159.     {
  4160.         // The List is empty, clear the panel display.
  4161.         fPanel->RemoveAll(ev);
  4162.     }
  4163. }
  4164.  
  4165. //------------------------------------------------------------------------------
  4166. // Method:        DoDialogBox
  4167. // Origin:        PanelEditor
  4168. //
  4169. // Description:    This method is calle by the part when the user selects
  4170. //                the "About PanelEditor…" menu items.
  4171. //------------------------------------------------------------------------------
  4172.  
  4173. void PanelEditor::DoDialogBox(     Environment*    ev,
  4174.                                 ODFrame*        frame,
  4175.                                 ODSShort        dialogID,
  4176.                                 ODUShort        errorNumber )
  4177. {
  4178.     SOM_Trace("PanelEditor","DoDialogBox");
  4179.  
  4180.     ODFrame* focusFrame = frame;
  4181.     ODSession*    session = ODGetSession(ev,fSelf);
  4182.     
  4183.     // If the calling method does not have a frame available to it, we need to
  4184.     // locate a frame to use for requesting the modal focus. Find the first valid
  4185.     // frame in our display frames list.
  4186.     if ( focusFrame == kODNULL )
  4187.     {
  4188.         CListIterator fiter(fDisplayFrames);
  4189.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  4190.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  4191.         {
  4192.             if ( proxy->FrameIsLoaded(ev) )
  4193.                 focusFrame = proxy->GetFrame(ev);
  4194.             if ( focusFrame ) break;
  4195.         }
  4196.     }
  4197.     
  4198.     // Our About box is modal so we must request the Modal focus to prevent
  4199.     // multiple modal dialogs being displayed simultaneously.
  4200.     
  4201.     if ( session->GetArbitrator(ev)->RequestFocus(ev, gGlobals->fModalFocus, focusFrame) )
  4202.     {
  4203.         DialogPtr    dialog;
  4204.         ODSShort    itemHit;
  4205.  
  4206.         // Dim the frontmost document window.
  4207.         session->GetWindowState(ev)->DeactivateFrontWindows(ev);
  4208.                 
  4209.         ODSLong rfRef;
  4210.         rfRef = BeginUsingLibraryResources();
  4211.         {            
  4212.             dialog = GetNewDialog(dialogID, kODNULL, (WindowPtr) -1L);
  4213.             
  4214.             if ( dialog )
  4215.             {
  4216.                 if ( errorNumber > 0 )
  4217.                 {
  4218.                     Handle    itemHandle;
  4219.                     Rect    itemRect;
  4220.                     short    itemType;
  4221.                     Str255    errStr;
  4222.                     
  4223.                     GetIndString(errStr, kErrorStringResID, errorNumber);
  4224.                     GetDialogItem(dialog, kErrStrFieldID, &itemType, &itemHandle, &itemRect);
  4225.                     SetDialogItemText(itemHandle, errStr);
  4226.                     
  4227.                     // We don't need the cancel button for an error dialog.
  4228.                     HideDialogItem(dialog, cancel);
  4229.  
  4230.                     SetDialogDefaultItem(dialog, ok);
  4231.                 }
  4232.                 
  4233.                 SetCursor(&ODQDGlobals.arrow);
  4234.                 ShowWindow(dialog);
  4235.                 ModalDialog(kODNULL, &itemHit);
  4236.                 DisposeDialog(dialog);
  4237.             }
  4238.             else
  4239.             {
  4240.                 // Could not load About box dialog... something is amiss.
  4241.                 SysBeep(2);
  4242.             }
  4243.         }
  4244.         EndUsingLibraryResources(rfRef);
  4245.         
  4246.         // Inform the Arbitrator that we no longer require the Modal focus.
  4247.         session->GetArbitrator(ev)->RelinquishFocus(ev, gGlobals->fModalFocus, focusFrame);
  4248.         
  4249.         // Hilite the frontmost document window.
  4250.         session->GetWindowState(ev)->ActivateFrontWindows(ev);
  4251.     }
  4252.     else
  4253.         // If we can't get the modal focus, then another modal dialog is
  4254.         // already being displayed.
  4255.         SysBeep(2);
  4256. }
  4257.  
  4258.  
  4259. #ifndef PE_ViewerBuild
  4260.  
  4261. //------------------------------------------------------------------------------
  4262. // Method:        DragEnter
  4263. // Origin:        ODPart
  4264. //
  4265. // Description:    This method is called on the part when the user is dragging data
  4266. //                over the "active" areas of the part (ie. the list frame).
  4267. //
  4268. //                The part displays dragging feedback, but does not check the drag
  4269. //                contents
  4270. //------------------------------------------------------------------------------
  4271.  
  4272. ODDragResult PanelEditor::DragEnter(Environment *ev, ODDragItemIterator* /*dragInfo*/,
  4273.                                     ODFacet* facet, ODPoint* /*where*/)
  4274. {
  4275.     DragReference    dragRef;
  4276.     Rect            listRect;
  4277.     RgnHandle        dragHilite = ODNewRgn();
  4278.     
  4279.     TRY
  4280.         SetCursor(&ODQDGlobals.arrow);
  4281.     
  4282.         dragRef = ODGetSession(ev,fSelf)->GetDragAndDrop(ev)->GetDragReference(ev);
  4283.     
  4284.         // Focus the port for drawing.
  4285.         CFocusFrame initiateDrawing(ev, facet);
  4286.     
  4287.         // Get the bounding box of the frame in quickdraw coordinates.
  4288.         GetQDFrameBounds(ev, facet->GetFrame(ev), &listRect);
  4289.         
  4290.         // Move the right side of the rectangle inside the scrollbar;
  4291.         listRect.right -= 15;
  4292.         
  4293.         InsetRect(&listRect, 1, 1);
  4294.         RectRgn(dragHilite, &listRect);
  4295.         
  4296.         // Show the Mac Drag Mgr highlighting in our frame.
  4297.         ShowDragHilite(dragRef, dragHilite, true);
  4298.  
  4299.     CATCH_ALL
  4300.     ENDTRY
  4301.     
  4302.     ODDisposeHandle((ODHandle)dragHilite);
  4303.  
  4304.     return kODTrue;
  4305. }
  4306.  
  4307. //------------------------------------------------------------------------------
  4308. // Method:        DoDialogBox
  4309. // Origin:        ODPart
  4310. //
  4311. // Description:    This method is calle by the part when the user selects
  4312. //------------------------------------------------------------------------------
  4313.  
  4314. ODDragResult PanelEditor::DragWithin(Environment *ev, ODDragItemIterator* /*dragInfo*/,
  4315.                                     ODFacet* /*facet*/, ODPoint* /*where*/)
  4316. {
  4317.     return kODTrue;
  4318. }
  4319.  
  4320.  
  4321. //------------------------------------------------------------------------------
  4322. // Method:        DoDialogBox
  4323. //
  4324. // Description:    This method is calle by the part when the user selects
  4325. //------------------------------------------------------------------------------
  4326.  
  4327. void PanelEditor::DragLeave(Environment *ev, ODFacet* facet, ODPoint* /*where*/)
  4328. {
  4329.     DragReference dragRef = 
  4330.             ODGetSession(ev,fSelf)->GetDragAndDrop(ev)->GetDragReference(ev);
  4331.  
  4332.     // Focus the port for drawing.
  4333.     CFocusFrame initiateDrawing(ev, facet);        
  4334.  
  4335.     // Hide the Mac Drag Mgr highlighting.
  4336.     HideDragHilite(dragRef);
  4337. }
  4338.  
  4339. //------------------------------------------------------------------------------
  4340. // Method:        Drop
  4341. //
  4342. // Description:    This method is calle by the part when the user selects
  4343. //------------------------------------------------------------------------------
  4344.  
  4345. ODDropResult PanelEditor::Drop(Environment *ev, ODDragItemIterator* dropInfo,
  4346.                                     ODFacet* facet, ODPoint* where)
  4347. {
  4348.     DragReference    dragRef;
  4349.     ODDropResult    result = kODDropFail;
  4350.     ODCloneKind        method;
  4351.     ODFrame*        frame = facet->GetFrame(ev);
  4352.     ODSession*        session = ODGetSession(ev,fSelf);
  4353.  
  4354.     // Determine the nature of the drag (copy vs. move).
  4355.     {
  4356.         ODBoolean    option;
  4357.         ODBoolean    control;
  4358.         ODSShort    mouseDownModifiers;
  4359.         ODSShort    mouseUpModifiers;
  4360.         ODULong        dragAttributes;
  4361.         
  4362.         dragAttributes = session->GetDragAndDrop(ev)->GetDragAttributes(ev);
  4363.         dragRef = session->GetDragAndDrop(ev)->GetDragReference(ev);
  4364.         
  4365.         GetDragModifiers(dragRef, 0L, &mouseDownModifiers, &mouseUpModifiers);    
  4366.         option = (mouseDownModifiers & optionKey) || (mouseUpModifiers & optionKey);
  4367.         control = (mouseDownModifiers & controlKey) || (mouseUpModifiers & controlKey);
  4368.         
  4369.         if ( control ) result = kODDropMove;
  4370.         else if ( option ) result = kODDropCopy;
  4371.         else result = kODDropMove;
  4372.         
  4373.         // The user dropped the item in the source frame.
  4374.         if ( !control && kODDropMove && (dragAttributes & kODDragIsInSourceFrame) )
  4375.             result = kODDropFail;
  4376.     }
  4377.  
  4378.     // Focus the port for drawing.
  4379.     CFocusFrame initiateDrawing(ev, facet);        
  4380.  
  4381.     // hide drag hilite
  4382.     HideDragHilite(dragRef);
  4383.  
  4384.     // If the drop is valid, process it.
  4385.     if ( result != kODDropFail )
  4386.     {
  4387.         // Determine what to tell the draft if we need to clone parts and/or
  4388.         // frames from the Drag&Drop su.
  4389.         method = (result == kODDropMove ? kODCloneDropMove : kODCloneDropCopy);
  4390.         
  4391.         // Clear the current selection.
  4392.         fSelection->Empty(ev);
  4393.         
  4394.         // Read in the data from each of the Drag & Drop StorageUnits.
  4395.         for (ODStorageUnit* dragSU = dropInfo->First(ev); dragSU; dragSU = dropInfo->Next(ev))
  4396.         {
  4397.             ODDraft*    fromDraft = dragSU->GetDraft(ev);
  4398.             ODDraft*    toDraft = fSelf->GetStorageUnit(ev)->GetDraft(ev);
  4399.             ODDraftKey    draftKey;
  4400.             ODID        partID;
  4401.             
  4402.             ODVolatile(fromDraft);
  4403.             ODVolatile(draftKey);
  4404.             
  4405.             // Since we only allow embedding of other parts, it makes sense to check
  4406.             // for a "content" property in each storage unit before trying to embed
  4407.             // it. Otherwise, we might end up with the "gray box" part.
  4408.             
  4409.             if ( dragSU->Exists(ev, kODPropContents, kODNULL, 0) )
  4410.             {
  4411.                 draftKey = fromDraft->BeginClone(ev, toDraft, kODNULL, method);
  4412.  
  4413.                 TRY
  4414.                     partID = fromDraft->Clone(ev, draftKey, dragSU->GetID(ev), 0, 0);
  4415.                     fromDraft->EndClone(ev, draftKey);
  4416.                     
  4417.                     // Create a proxy for the new item
  4418.                     this->EmbedNewItem(ev, facet, partID);
  4419.             
  4420.                     // Allow the user to undo/redo the drag operation.
  4421.                     fSelection->PushUndoState(ev, kUndoDrop, kODSingleAction);
  4422.                 CATCH_ALL
  4423.                     fromDraft->AbortClone(ev, draftKey);
  4424.                     RERAISE;
  4425.                 ENDTRY
  4426.             }
  4427.         }
  4428.         
  4429.         // Verify list item positions and adjust the scrollbar setting.
  4430.         fList->AdjustItemPositions(ev);
  4431.         fList->AdjustScrollbar(ev);
  4432.         
  4433.         //$$$$$ this shoud be optimized to invalidate just the new item area.
  4434.         frame->Invalidate(ev, kODNULL, kODNULL);
  4435.         
  4436.         // Dirty the draft.
  4437.         this->SetDirty(ev);
  4438.     }    
  4439.     
  4440.     return result;
  4441. }
  4442.  
  4443. #endif // #ifndef PE_ViewerBuild
  4444.  
  4445. //------------------------------------------------------------------------------
  4446. // Method:        DoPartInfo
  4447. //
  4448. // Description:    This method is calle by the part when the user selects
  4449. //------------------------------------------------------------------------------
  4450.  
  4451. void PanelEditor::DoPartInfo(Environment* ev, ODFrame* frame)
  4452. {
  4453.     SOM_Trace("PanelEditor","DoPartInfo");
  4454.  
  4455.     // Focus for drawing. If the user changes the name we want to
  4456.     // update it instantaneously.
  4457.     CFocusFrame initiateDrawing(ev, this->GetActiveFacetForFrame(ev, frame));
  4458.  
  4459.     // Display (serially) the part info dialog for the items
  4460.     // in the selection.
  4461.     fSelection->ShowPartInfo(ev, frame);    
  4462. }
  4463.  
  4464. //------------------------------------------------------------------------------
  4465. // Method:        DoCut
  4466. //
  4467. // Description:    This method is calle by the part when the user selects
  4468. //------------------------------------------------------------------------------
  4469.  
  4470. void PanelEditor::DoCut(Environment* ev, ODFrame* frame)
  4471. {
  4472.     SOM_Trace("PanelEditor","DoCut");
  4473.  
  4474.     // Get a valid item to add to the selection.
  4475.     CListItem* item = this->GetItemNearSelection();
  4476.  
  4477.     // Clear the items in the selection.
  4478.     fSelection->Cut(ev, frame);
  4479.     
  4480.     // Verify list item positions.
  4481.     fList->AdjustItemPositions(ev);
  4482.     // Adjust the scrollbar setting.
  4483.     fList->AdjustScrollbar(ev);
  4484.     // Update the selection.
  4485.     this->UpdateSelection(ev, item);
  4486.         
  4487.     // Force redrawing.
  4488.     frame->Invalidate(ev, kODNULL, kODNULL);
  4489.     
  4490.     // Dirty the draft.
  4491.     this->SetDirty(ev);
  4492. }
  4493.  
  4494. //------------------------------------------------------------------------------
  4495. // Method:        DoCopy
  4496. //
  4497. // Description:    This method is calle by the part when the user selects
  4498. //------------------------------------------------------------------------------
  4499.  
  4500. void PanelEditor::DoCopy(Environment* ev, ODFrame* frame)
  4501. {
  4502.     SOM_Trace("PanelEditor","DoCopy");
  4503.  
  4504.     // Copy the items in the selection.
  4505.     fSelection->Copy(ev, frame);
  4506. }
  4507.  
  4508. //------------------------------------------------------------------------------
  4509. // Method:        DoPaste
  4510. //
  4511. // Description:    This method is calle by the part when the user selects
  4512. //------------------------------------------------------------------------------
  4513.  
  4514. void PanelEditor::DoPaste(Environment* ev, ODFrame* frame)
  4515. {
  4516.     SOM_Trace("PanelEditor","DoPaste");
  4517.  
  4518.     ODFacet* facet = this->GetActiveFacetForFrame(ev, frame);
  4519.  
  4520.     // Acquire the clipboard focus and write the selection to it.
  4521.     
  4522.     ODSession* session = ODGetSession(ev,fSelf);
  4523.     ODArbitrator* arbitrator = session->GetArbitrator(ev);
  4524.     ODClipboard* clipboard = session->GetClipboard(ev);
  4525.  
  4526.     if ( arbitrator->RequestFocus(ev, gGlobals->fClipboardFocus, frame) )
  4527.     {
  4528.         ODStorageUnit* su = clipboard->GetContentStorageUnit(ev);    
  4529.  
  4530.         ODDraft*    fromDraft = su->GetDraft(ev);
  4531.         ODDraft*    toDraft = ODGetDraft(ev,fSelf);
  4532.         ODDraftKey    draftKey;
  4533.         ODID        partID;
  4534.         
  4535.         ODVolatile(fromDraft);
  4536.         ODVolatile(draftKey);
  4537.         
  4538.         // Focus the port for drawing.
  4539.         CFocusFrame initiateDrawing(ev, facet);        
  4540.     
  4541.         // Clear the current selection.
  4542.         fSelection->Empty(ev);
  4543.         
  4544.         draftKey = fromDraft->BeginClone(ev, toDraft, kODNULL, kODClonePaste);
  4545.  
  4546.         TRY
  4547.             partID = fromDraft->Clone(ev, draftKey, su->GetID(ev), 0, 0);
  4548.             fromDraft->EndClone(ev, draftKey);
  4549.             
  4550.             // Create a proxy for the new item.
  4551.             this->EmbedNewItem(ev, facet, partID);
  4552.             
  4553.             // Allow the user to undo/redo the clipboard operation.
  4554.             fSelection->PushUndoState(ev, kUndoPaste, kODSingleAction);
  4555.             
  4556.             // Adjust the clipshape for the new item.
  4557.             fList->ClipItems(ev);
  4558.         CATCH_ALL
  4559.             fromDraft->AbortClone(ev, draftKey);
  4560.         ENDTRY
  4561.     
  4562.         arbitrator->RelinquishFocus(ev, gGlobals->fClipboardFocus, frame);
  4563.     }
  4564.     
  4565.     // Adjust the scrollbar settings.
  4566.     fList->AdjustScrollbar(ev);
  4567.     
  4568.     // Dirty the draft.
  4569.     this->SetDirty(ev);
  4570. }
  4571.  
  4572. //------------------------------------------------------------------------------
  4573. // Method:        DoPasteAs
  4574. //
  4575. // Description:    This method is calle by the part when the user selects
  4576. //------------------------------------------------------------------------------
  4577.  
  4578. void PanelEditor::DoPasteAs(Environment* ev, ODFrame* frame)
  4579. {
  4580.     SOM_Trace("PanelEditor","DoPasteAs");
  4581.     
  4582.     // $$$$$ dialog
  4583.     
  4584.     // 
  4585.     this->DoPaste(ev, frame);
  4586.     
  4587.     // Verify list item positions and adjust the scrollbar setting.
  4588.     fList->AdjustItemPositions(ev);
  4589.     fList->AdjustScrollbar(ev);
  4590.     
  4591.     // Dirty the draft.
  4592.     this->SetDirty(ev);
  4593. }
  4594.  
  4595. //------------------------------------------------------------------------------
  4596. // Method:        DoClear
  4597. //
  4598. // Description:    This method is calle by the part when the user selects
  4599. //------------------------------------------------------------------------------
  4600.  
  4601. void PanelEditor::DoClear(Environment* ev, ODFrame* frame)
  4602. {
  4603.     SOM_Trace("PanelEditor","DoClear");
  4604.     
  4605.     // Get a valid item to add to the selection.
  4606.     CListItem* item = this->GetItemNearSelection();
  4607.  
  4608.     // Clear the items in the selection.
  4609.     fSelection->Clear(ev, frame);
  4610.     
  4611.     // Verify list item positions.
  4612.     fList->AdjustItemPositions(ev);
  4613.     // Adjust the scrollbar setting.
  4614.     fList->AdjustScrollbar(ev);
  4615.     // Update the selection.
  4616.     this->UpdateSelection(ev, item);
  4617.     
  4618.     // Force redrawing.
  4619.     frame->Invalidate(ev, kODNULL, kODNULL);
  4620.     
  4621.     // Dirty the draft.
  4622.     this->SetDirty(ev);
  4623. }
  4624.  
  4625. //------------------------------------------------------------------------------
  4626. // Method:        UndoAction
  4627. //
  4628. // Description:    This method is calle by the part when the user selects
  4629. //------------------------------------------------------------------------------
  4630.  
  4631. void PanelEditor::UndoAction(Environment* ev, ODActionData* action)
  4632. {
  4633.     SOM_Trace("PanelEditor","UndoAction");
  4634.  
  4635.     fSelection->Undo(ev, ((CUndo*)action->_buffer));    
  4636.     
  4637.     // Adjust the scrollbar settings.
  4638.     //fList->AdjustScrollbar(ev);
  4639. }
  4640.  
  4641. //------------------------------------------------------------------------------
  4642. // Method:        RedoAction
  4643. //
  4644. // Description:    This method is calle by the part when the user selects
  4645. //------------------------------------------------------------------------------
  4646.  
  4647. void PanelEditor::RedoAction(Environment* ev, ODActionData* action)
  4648. {
  4649.     SOM_Trace("PanelEditor","RedoAction");
  4650.  
  4651.     fSelection->Redo(ev, ((CUndo*)action->_buffer));
  4652.     
  4653.     // Adjust the scrollbar settings.
  4654.     //fList->AdjustScrollbar(ev);
  4655. }
  4656.  
  4657. //------------------------------------------------------------------------------
  4658. // Method:        DisposeActionState
  4659. //
  4660. // Description:    This method is calle by the part when the user selects
  4661. //------------------------------------------------------------------------------
  4662.  
  4663. void PanelEditor::DisposeActionState(Environment* ev, ODActionData* action,
  4664.                                         ODDoneState doneState)
  4665. {
  4666.     SOM_Trace("PanelEditor","DisposeActionState");
  4667.  
  4668.     CUndo* undoObj = (*((CUndo**)action->_buffer));
  4669.     delete undoObj;
  4670. }
  4671.  
  4672.  
  4673.  
  4674.  
  4675.  
  4676.  
  4677.  
  4678.  
  4679.  
  4680.